summaryrefslogtreecommitdiff
path: root/src/spriteloader
diff options
context:
space:
mode:
Diffstat (limited to 'src/spriteloader')
-rw-r--r--src/spriteloader/grf.cpp96
-rw-r--r--src/spriteloader/grf.hpp18
-rw-r--r--src/spriteloader/spriteloader.hpp34
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 */