src/spriteloader/grf.cpp
changeset 6852 439563b70fd3
child 6872 0a4a20ef71c3
equal deleted inserted replaced
6851:0a0a094fb9f1 6852:439563b70fd3
       
     1 #include "../stdafx.h"
       
     2 #include "../gfx.h"
       
     3 #include "../fileio.h"
       
     4 #include "../debug.h"
       
     5 #include "grf.hpp"
       
     6 
       
     7 bool SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint32 file_pos)
       
     8 {
       
     9 	/* Open the right file and go to the correct position */
       
    10 	FioSeekToFile(file_pos);
       
    11 
       
    12 	/* Read the size and type */
       
    13 	int num = FioReadWord();
       
    14 	byte type = FioReadByte();
       
    15 
       
    16 	/* Type 0xFF indicates either a colormap or some other non-sprite info; we do not handle them here */
       
    17 	if (type == 0xFF) return false;
       
    18 
       
    19 	sprite->height = FioReadByte();
       
    20 	sprite->width  = FioReadWord();
       
    21 	sprite->x_offs = FioReadWord();
       
    22 	sprite->y_offs = FioReadWord();
       
    23 
       
    24 	/* 0x02 indicates it is a compressed sprite, so we can't rely on 'num' to be valid.
       
    25 	 *  In case it is uncompressed, the size is 'num' - 8 (header-size). */
       
    26 	num = (type & 0x02) ? sprite->width * sprite->height : num - 8;
       
    27 
       
    28 	/* XXX -- We should use a pre-located memory segment for this, malloc/free is pretty expensive */
       
    29 	byte *dest_orig = MallocT<byte>(num);
       
    30 	byte *dest = dest_orig;
       
    31 
       
    32 	/* Read the file, which has some kind of compression */
       
    33 	while (num > 0) {
       
    34 		int8 code = FioReadByte();
       
    35 
       
    36 		if (code >= 0) {
       
    37 			/* Plain bytes to read */
       
    38 			int size = (code == 0) ? 0x80 : code;
       
    39 			num -= size;
       
    40 			for (; size > 0; size--) {
       
    41 				*dest = FioReadByte();
       
    42 				dest++;
       
    43 			}
       
    44 		} else {
       
    45 			/* Copy bytes from earlier in the sprite */
       
    46 			const uint data_offset = ((code & 7) << 8) | FioReadByte();
       
    47 			int size = -(code >> 3);
       
    48 			num -= size;
       
    49 			for (; size > 0; size--) {
       
    50 				*dest = *(dest - data_offset);
       
    51 				dest++;
       
    52 			}
       
    53 		}
       
    54 	}
       
    55 
       
    56 	assert(num == 0);
       
    57 
       
    58 	sprite->data = CallocT<SpriteLoader::CommonPixel>(sprite->width * sprite->height);
       
    59 
       
    60 	/* When there are transparency pixels, this format has an other trick.. decode it */
       
    61 	if (type & 0x08) {
       
    62 		for (int y = 0; y < sprite->height; y++) {
       
    63 			bool last_item = false;
       
    64 			/* Look up in the header-table where the real data is stored for this row */
       
    65 			int offset = (dest_orig[y * 2 + 1] << 8) | dest_orig[y * 2];
       
    66 			/* Go to that row */
       
    67 			dest = &dest_orig[offset];
       
    68 
       
    69 			do {
       
    70 				SpriteLoader::CommonPixel *data;
       
    71 				/* Read the header:
       
    72 				 *  0 .. 14  - length
       
    73 				 *  15       - last_item
       
    74 				 *  16 .. 31 - transparency bytes */
       
    75 				last_item  = ((*dest) & 0x80) != 0;
       
    76 				int length =  (*dest++) & 0x7F;
       
    77 				int skip   =   *dest++;
       
    78 
       
    79 				data = &sprite->data[y * sprite->width + skip];
       
    80 
       
    81 				for (int x = 0; x < length; x++) {
       
    82 					data->m = *dest;
       
    83 					dest++;
       
    84 					data++;
       
    85 				}
       
    86 			} while (!last_item);
       
    87 		}
       
    88 	} else {
       
    89 		dest = dest_orig;
       
    90 		for (int i = 0; i < sprite->width * sprite->height; i++)
       
    91 			sprite->data[i].m = dest[i];
       
    92 	}
       
    93 
       
    94 	free(dest_orig);
       
    95 	return true;
       
    96 }