diff options
Diffstat (limited to 'src/spriteloader')
-rw-r--r-- | src/spriteloader/grf.cpp | 96 | ||||
-rw-r--r-- | src/spriteloader/grf.hpp | 18 | ||||
-rw-r--r-- | src/spriteloader/spriteloader.hpp | 34 |
3 files changed, 148 insertions, 0 deletions
diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp new file mode 100644 index 000000000..4d412d6ea --- /dev/null +++ b/src/spriteloader/grf.cpp @@ -0,0 +1,96 @@ +#include "../stdafx.h" +#include "../gfx.h" +#include "../fileio.h" +#include "../debug.h" +#include "grf.hpp" + +bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint32 file_pos) +{ + /* Open the right file and go to the correct position */ + FioSeekToFile(file_pos); + + /* Read the size and type */ + int num = FioReadWord(); + byte type = FioReadByte(); + + /* Type 0xFF indicates either a colormap or some other non-sprite info; we do not handle them here */ + if (type == 0xFF) return false; + + sprite->height = FioReadByte(); + sprite->width = FioReadWord(); + sprite->x_offs = FioReadWord(); + sprite->y_offs = FioReadWord(); + + /* 0x02 indicates it is a compressed sprite, so we can't rely on 'num' to be valid. + * In case it is uncompressed, the size is 'num' - 8 (header-size). */ + num = (type & 0x02) ? sprite->width * sprite->height : num - 8; + + /* XXX -- We should use a pre-located memory segment for this, malloc/free is pretty expensive */ + byte *dest_orig = MallocT<byte>(num); + byte *dest = dest_orig; + + /* Read the file, which has some kind of compression */ + while (num > 0) { + int8 code = FioReadByte(); + + if (code >= 0) { + /* Plain bytes to read */ + int size = (code == 0) ? 0x80 : code; + num -= size; + for (; size > 0; size--) { + *dest = FioReadByte(); + dest++; + } + } else { + /* Copy bytes from earlier in the sprite */ + const uint data_offset = ((code & 7) << 8) | FioReadByte(); + int size = -(code >> 3); + num -= size; + for (; size > 0; size--) { + *dest = *(dest - data_offset); + dest++; + } + } + } + + assert(num == 0); + + sprite->data = CallocT<SpriteLoader::CommonPixel>(sprite->width * sprite->height); + + /* When there are transparency pixels, this format has an other trick.. decode it */ + if (type & 0x08) { + for (int y = 0; y < sprite->height; y++) { + bool last_item = false; + /* Look up in the header-table where the real data is stored for this row */ + int offset = (dest_orig[y * 2 + 1] << 8) | dest_orig[y * 2]; + /* Go to that row */ + dest = &dest_orig[offset]; + + do { + SpriteLoader::CommonPixel *data; + /* Read the header: + * 0 .. 14 - length + * 15 - last_item + * 16 .. 31 - transparency bytes */ + last_item = ((*dest) & 0x80) != 0; + int length = (*dest++) & 0x7F; + int skip = *dest++; + + data = &sprite->data[y * sprite->width + skip]; + + for (int x = 0; x < length; x++) { + data->m = *dest; + dest++; + data++; + } + } while (!last_item); + } + } else { + dest = dest_orig; + for (int i = 0; i < sprite->width * sprite->height; i++) + sprite->data[i].m = dest[i]; + } + + free(dest_orig); + return true; +} diff --git a/src/spriteloader/grf.hpp b/src/spriteloader/grf.hpp new file mode 100644 index 000000000..27083f993 --- /dev/null +++ b/src/spriteloader/grf.hpp @@ -0,0 +1,18 @@ +/* $Id$ */ + +/** @file grf.hpp */ + +#ifndef SPRITELOADER_GRF_HPP +#define SPRITELOADER_GRF_HPP + +#include "spriteloader.hpp" + +class SpriteLoaderGrf : public SpriteLoader { +public: + /** + * Load a sprite from the disk and return a sprite struct which is the same for all loaders. + */ + bool LoadSprite(SpriteLoader::Sprite *sprite, uint32 file_pos); +}; + +#endif /* SPRITELOADER_GRF_HPP */ diff --git a/src/spriteloader/spriteloader.hpp b/src/spriteloader/spriteloader.hpp new file mode 100644 index 000000000..658277236 --- /dev/null +++ b/src/spriteloader/spriteloader.hpp @@ -0,0 +1,34 @@ +/* $Id$ */ + +/** @file spriteloader.hpp */ + +#ifndef SPRITELOADER_HPP +#define SPRITELOADER_HPP + +class SpriteLoader { +public: + struct CommonPixel { + uint8 r; ///< Red-channel + uint8 g; ///< Green-channel + uint8 b; ///< Blue-channel + uint8 a; ///< Alpha-channel + uint8 m; ///< Remap-channel + }; + + struct Sprite { + uint16 height; ///< Height of the sprite + uint16 width; ///< Width of the sprite + int16 x_offs; ///< The x-offset of where the sprite will be drawn + int16 y_offs; ///< The y-offset of where the sprite will be drawn + SpriteLoader::CommonPixel *data; ///< The sprite itself + }; + + /** + * Load a sprite from the disk and return a sprite struct which is the same for all loaders. + */ + virtual bool LoadSprite(SpriteLoader::Sprite *sprite, uint32 file_pos) = 0; + + virtual ~SpriteLoader() { } +}; + +#endif /* SPRITELOADER_HPP */ |