peter1138@6872: /* $Id$ */ peter1138@6872: rubidium@9111: /** @file grf.cpp Reading graphics data from (New)GRF files. */ peter1138@6872: truelight@6852: #include "../stdafx.h" rubidium@8123: #include "../gfx_func.h" truelight@6852: #include "../fileio.h" truelight@6852: #include "../debug.h" rubidium@8130: #include "../core/alloc_func.hpp" truelight@6852: #include "grf.hpp" truelight@6852: rubidium@9390: bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos) truelight@6852: { truelight@6852: /* Open the right file and go to the correct position */ truelight@7570: FioSeekToFile(file_slot, file_pos); truelight@6852: truelight@6852: /* Read the size and type */ truelight@6852: int num = FioReadWord(); truelight@6852: byte type = FioReadByte(); truelight@6852: truelight@6852: /* Type 0xFF indicates either a colormap or some other non-sprite info; we do not handle them here */ truelight@6852: if (type == 0xFF) return false; truelight@6852: truelight@6852: sprite->height = FioReadByte(); truelight@6852: sprite->width = FioReadWord(); truelight@6852: sprite->x_offs = FioReadWord(); truelight@6852: sprite->y_offs = FioReadWord(); truelight@6852: truelight@6852: /* 0x02 indicates it is a compressed sprite, so we can't rely on 'num' to be valid. truelight@6852: * In case it is uncompressed, the size is 'num' - 8 (header-size). */ truelight@6852: num = (type & 0x02) ? sprite->width * sprite->height : num - 8; truelight@6852: truelight@6852: /* XXX -- We should use a pre-located memory segment for this, malloc/free is pretty expensive */ truelight@6852: byte *dest_orig = MallocT(num); truelight@6852: byte *dest = dest_orig; truelight@6852: truelight@6852: /* Read the file, which has some kind of compression */ truelight@6852: while (num > 0) { truelight@6852: int8 code = FioReadByte(); truelight@6852: truelight@6852: if (code >= 0) { truelight@6852: /* Plain bytes to read */ truelight@6852: int size = (code == 0) ? 0x80 : code; truelight@6852: num -= size; truelight@6852: for (; size > 0; size--) { truelight@6852: *dest = FioReadByte(); truelight@6852: dest++; truelight@6852: } truelight@6852: } else { truelight@6852: /* Copy bytes from earlier in the sprite */ truelight@6852: const uint data_offset = ((code & 7) << 8) | FioReadByte(); truelight@6852: int size = -(code >> 3); truelight@6852: num -= size; truelight@6852: for (; size > 0; size--) { truelight@6852: *dest = *(dest - data_offset); truelight@6852: dest++; truelight@6852: } truelight@6852: } truelight@6852: } truelight@6852: truelight@6852: assert(num == 0); truelight@6852: truelight@6852: sprite->data = CallocT(sprite->width * sprite->height); truelight@6852: truelight@6852: /* When there are transparency pixels, this format has an other trick.. decode it */ truelight@6852: if (type & 0x08) { truelight@6852: for (int y = 0; y < sprite->height; y++) { truelight@6852: bool last_item = false; truelight@6852: /* Look up in the header-table where the real data is stored for this row */ truelight@6852: int offset = (dest_orig[y * 2 + 1] << 8) | dest_orig[y * 2]; truelight@6852: /* Go to that row */ truelight@6852: dest = &dest_orig[offset]; truelight@6852: truelight@6852: do { truelight@6852: SpriteLoader::CommonPixel *data; truelight@6852: /* Read the header: truelight@6852: * 0 .. 14 - length truelight@6852: * 15 - last_item truelight@6852: * 16 .. 31 - transparency bytes */ truelight@6852: last_item = ((*dest) & 0x80) != 0; truelight@6852: int length = (*dest++) & 0x7F; truelight@6852: int skip = *dest++; truelight@6852: truelight@6852: data = &sprite->data[y * sprite->width + skip]; truelight@6852: truelight@6852: for (int x = 0; x < length; x++) { truelight@6852: data->m = *dest; truelight@6852: dest++; truelight@6852: data++; truelight@6852: } truelight@6852: } while (!last_item); truelight@6852: } truelight@6852: } else { truelight@6852: dest = dest_orig; truelight@6852: for (int i = 0; i < sprite->width * sprite->height; i++) truelight@6852: sprite->data[i].m = dest[i]; truelight@6852: } truelight@6852: truelight@6889: /* Make sure to mark all transparent pixels transparent on the alpha channel too */ truelight@6889: for (int i = 0; i < sprite->width * sprite->height; i++) truelight@6889: if (sprite->data[i].m != 0) sprite->data[i].a = 0xFF; truelight@6889: truelight@6852: free(dest_orig); truelight@6852: return true; truelight@6852: }