Cyberion
Administrator
well was browsing some russian coder's forums and stumbled upon very interesting code.
The guy managed to understand the code of Crusader sprites, read thema nd convert to TGA files. He wrote a code for a tool, which could be compiled into an easy convertor. Here is the code. LAter on I'll translate russian text remarks into english ones. So far i'm going to sleep
The source adress - http://www.gamedev.ru/code/forum/?id=64785
The guy managed to understand the code of Crusader sprites, read thema nd convert to TGA files. He wrote a code for a tool, which could be compiled into an easy convertor. Here is the code. LAter on I'll translate russian text remarks into english ones. So far i'm going to sleep
The source adress - http://www.gamedev.ru/code/forum/?id=64785
Code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
// sprites from Crusader 8-bit palette
// the palette used in the game from gamepal.pal, just in case here it is in the format for tga
unsigned char palette[] = {
0x00,0x00,0x00,0xbc,0xfc,0xfc,0x20,0xf0,0xf8,0x1c,0xc8,0xfc,0x14,0xa4,0xfc,0x0c,0x7c,0xfc,0x08,0x58,0xfc,0x00,0x30,0xfc,
0x00,0x00,0x00,0x44,0xfc,0xfc,0x50,0x54,0xfc,0x50,0xa4,0x4c,0xbc,0x74,0x00,0xcc,0xfc,0xfc,0xc8,0xfc,0xfc,0xd4,0xfc,0xfc,
0xfc,0xfc,0xfc,0xe8,0xe8,0xe8,0xd4,0xd4,0xd4,0xc0,0xc0,0xc0,0xac,0xac,0xac,0x98,0x98,0x98,0x88,0x88,0x88,0x74,0x74,0x74,
0x64,0x64,0x64,0x58,0x58,0x58,0x48,0x48,0x48,0x38,0x38,0x38,0x2c,0x2c,0x2c,0x1c,0x1c,0x1c,0x0c,0x0c,0x0c,0x00,0x00,0x00,
0x44,0x6c,0xd4,0x44,0x64,0xb8,0x44,0x5c,0x9c,0x48,0x54,0x84,0x48,0x4c,0x68,0x4c,0x40,0x4c,0x4c,0x38,0x34,0x4c,0x30,0x18,
0x4c,0xb4,0xd8,0x4c,0xa4,0xc4,0x50,0x90,0xb4,0x54,0x80,0xa0,0x54,0x70,0x8c,0x58,0x60,0x7c,0x5c,0x50,0x68,0x5c,0x3c,0x54,
0xe8,0xd8,0xd8,0xdc,0xc8,0xc4,0xcc,0xbc,0xb4,0xc0,0xac,0xa4,0xb4,0x9c,0x90,0xa4,0x8c,0x80,0x98,0x80,0x6c,0x8c,0x70,0x5c,
0x7c,0x60,0x4c,0x6c,0x54,0x40,0x58,0x44,0x34,0x48,0x38,0x2c,0x38,0x2c,0x20,0x24,0x1c,0x14,0x14,0x10,0x0c,0x20,0xf0,0xf8,
0xdc,0x60,0x00,0x70,0x30,0x00,0x20,0xe0,0xf8,0x08,0x20,0x88,0x0c,0xb4,0x00,0x08,0x6c,0x00,0x1c,0xd4,0xfc,0x18,0xc4,0xfc,
0x88,0xb0,0xb4,0x74,0x9c,0xa0,0x60,0x88,0x8c,0x48,0x74,0x74,0x3c,0x5c,0x5c,0x2c,0x44,0x44,0x1c,0x28,0x28,0x0c,0x14,0x14,
0xd8,0xd8,0xd8,0xc8,0xc8,0xd4,0xb8,0xb8,0xc8,0xa8,0xa8,0xb8,0x98,0x98,0xa8,0x88,0x88,0x9c,0x78,0x78,0x8c,0x68,0x68,0x7c,
0x5c,0x5c,0x74,0x50,0x50,0x70,0x44,0x44,0x68,0x38,0x38,0x60,0x28,0x28,0x4c,0x1c,0x1c,0x38,0x10,0x10,0x24,0x18,0xb4,0xfc,
0xe8,0xfc,0xfc,0xc8,0xec,0xfc,0x14,0xa8,0xfc,0x10,0x98,0xfc,0x64,0xbc,0xfc,0x44,0xac,0xfc,0x20,0x9c,0xfc,0x10,0x88,0xfc,
0x00,0x78,0xe0,0x00,0x64,0xc8,0x00,0x54,0xac,0x00,0x40,0x90,0x00,0x2c,0x78,0x00,0x18,0x5c,0x00,0x04,0x40,0x00,0x00,0x28,
0xb0,0xbc,0xd8,0xa0,0xac,0xcc,0x90,0x9c,0xc4,0x80,0x8c,0xb8,0x70,0x7c,0xac,0x64,0x70,0xa4,0x5c,0x64,0x90,0x58,0x58,0x7c,
0x54,0x50,0x6c,0x4c,0x44,0x58,0x48,0x3c,0x44,0x44,0x30,0x34,0x34,0x28,0x28,0x28,0x1c,0x1c,0x18,0x10,0x10,0x0c,0x08,0x04,
0xd8,0xec,0xd4,0xc4,0xd8,0xb8,0xb0,0xc0,0x98,0x9c,0xa8,0x7c,0x88,0x90,0x5c,0x68,0x6c,0x40,0x48,0x44,0x20,0x24,0x1c,0x04,
0xac,0xc8,0xfc,0x94,0xac,0xe8,0x80,0x90,0xd4,0x68,0x74,0xbc,0x54,0x58,0xa8,0x40,0x40,0x90,0x30,0x28,0x70,0x1c,0x10,0x58,
0xa8,0xd0,0xdc,0xa0,0xc4,0xc8,0x94,0xb8,0xb4,0x8c,0xac,0xa0,0x84,0xa0,0x88,0x7c,0x94,0x74,0x74,0x88,0x60,0x68,0x7c,0x4c,
0x60,0x6c,0x44,0x54,0x60,0x3c,0x4c,0x50,0x30,0x40,0x44,0x28,0x34,0x34,0x1c,0x2c,0x28,0x14,0x20,0x18,0x0c,0x14,0x0c,0x00,
0x0c,0x78,0xfc,0xa8,0xdc,0xfc,0x94,0xd0,0xfc,0x80,0xc8,0xfc,0x80,0xb0,0xd8,0x7c,0x9c,0xb0,0x78,0x84,0x8c,0x78,0x70,0x64,
0x74,0x58,0x40,0x74,0x44,0x18,0x64,0x3c,0x14,0x54,0x30,0x10,0x44,0x28,0x0c,0x34,0x1c,0x08,0x24,0x14,0x04,0x0c,0x6c,0xfc,
0xcc,0xdc,0xf4,0xbc,0xd4,0xe8,0xa8,0xc8,0xdc,0x94,0xbc,0xcc,0x80,0xb0,0xc0,0x6c,0xa4,0xb0,0x60,0x94,0xa4,0x58,0x88,0x98,
0x4c,0x78,0x8c,0x40,0x68,0x7c,0x38,0x58,0x68,0x2c,0x48,0x58,0x20,0x38,0x48,0x14,0x28,0x34,0x08,0x18,0x24,0x00,0x04,0x10,
0xb8,0xe4,0xfc,0xa4,0xcc,0xf0,0x90,0xb4,0xe0,0x78,0x98,0xd0,0x64,0x80,0xc0,0x50,0x64,0xb0,0x38,0x4c,0xa0,0x24,0x34,0x90,
0x0c,0x18,0x84,0x0c,0x14,0x74,0x08,0x10,0x64,0x08,0x10,0x54,0x08,0x0c,0x44,0x04,0x08,0x34,0x04,0x04,0x24,0x04,0x04,0x18,
0xb0,0xd8,0xfc,0xa0,0xc4,0xf0,0x8c,0xb4,0xe4,0x7c,0xa4,0xd8,0x6c,0x90,0xcc,0x58,0x80,0xbc,0x48,0x6c,0xb0,0x44,0x60,0xa8,
0x40,0x58,0xa0,0x3c,0x4c,0x98,0x34,0x40,0x90,0x30,0x34,0x88,0x28,0x28,0x68,0x20,0x20,0x44,0x18,0x14,0x20,0x08,0x5c,0xfc,
0xbc,0xcc,0xfc,0xb0,0xc0,0xfc,0xa4,0xb4,0xfc,0x98,0xa8,0xf8,0x8c,0x9c,0xf8,0x80,0x90,0xf4,0x78,0x80,0xf4,0x6c,0x74,0xf4,
0x60,0x68,0xf0,0x54,0x5c,0xf0,0x48,0x50,0xec,0x3c,0x44,0xec,0x30,0x38,0xec,0x28,0x2c,0xe8,0x1c,0x1c,0xe8,0x10,0x10,0xe4,
0x08,0x08,0xe4,0x08,0x08,0xd4,0x04,0x04,0xc4,0x04,0x04,0xb8,0x04,0x04,0xa8,0x04,0x04,0x98,0x04,0x04,0x88,0x04,0x04,0x78,
0x04,0x04,0x6c,0x04,0x04,0x5c,0x04,0x04,0x4c,0x04,0x4c,0xfc,0x04,0x40,0xfc,0x00,0x00,0x20,0x00,0x30,0xfc,0xac,0xb8,0x30
};
#pragma pack(1)
// array of indicators for the sprite animation
struct frame_ptr
{
unsigned frame_offset;
unsigned frame_size;
};
// sprite header
struct CrusaderSprite{
unsigned version; // ??, always 0x0101
unsigned short frame_cnt;
frame_ptr frames[];
};
// header of the animation frame
struct CrusaderSpriteFrame
{
unsigned short resource_id;
unsigned short frame_num;
unsigned unknown; // ??, i have no idea what it is
unsigned flags;
unsigned width;
unsigned height;
unsigned unknown2, unknown3; // probably its a sprites hotspot
unsigned row_offsets[/* height */];
};
struct TGAHeader{
unsigned char id_len;
unsigned char colormap_type;
unsigned char image_type;
unsigned short cm_first_entry;
unsigned short cm_length;
unsigned char cm_entry_size;
unsigned short x_origin;
unsigned short y_origin;
unsigned short width;
unsigned short height;
unsigned char depth;
unsigned char img_desc;
};
#pragma pack()
int main(int argc, char **argv)
{
int inf = open(argv[1], O_RDONLY|O_BINARY);
int len = lseek(inf, 0, SEEK_END); lseek(inf, 0, SEEK_SET);
char *res = new char[len];
read(inf, res, len);
close(inf);
TGAHeader tga;
memset(&tga, 0, sizeof(tga));
tga.colormap_type=1;
tga.image_type=1;
tga.cm_length=0x100;
tga.cm_entry_size=0x18;
tga.depth=8;
tga.img_desc=0x20;
CrusaderSprite &sprite=(CrusaderSprite&)res[0];
for(int cur_frame=0; cur_frame<sprite.frame_cnt; ++cur_frame)
{
unsigned frame_offset = sprite.frames[cur_frame].frame_offset & 0x7fffffff; // 0x80000000 always the same. what is the flag?
CrusaderSpriteFrame &frame = (CrusaderSpriteFrame &) res[frame_offset];
char frame_file_name[1024];
snprintf(frame_file_name, sizeof(frame_file_name), "%04x_%04x.tga", frame.resource_id, frame.frame_num);
printf("Saving %s...\n", frame_file_name);
int ouf = open(frame_file_name, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE);
unsigned sprite_data_len = frame.width*frame.height;
unsigned char *sprite_data = new unsigned char[frame.width*frame.height];
// background color, let it be green
memset(sprite_data, 0x44, sprite_data_len);
unsigned char *src, *dst;
for(int row=0; row<frame.height; ++row)
{
// the deviation of the point calculated from the row element of array and not from the beginning
// array of frame
src = (unsigned char *)&frame.row_offsets[row] + frame.row_offsets[row];
dst = &sprite_data[row*frame.width];
// in the beginning of row src[0] transparent pixels
int col = *src;
dst += *src++;
while(col<frame.width)
{
// rle chunks, first byte is a lenght (and optional the flag is copy/fill), futher is the chain of copied bytes
// byte - the number of transparent pixels after the chain
int chunk_len = *src++;
bool fill = false;
// byte of the lenght of chunk, includes copy/fill flag
if(frame.flags&1)
{
fill = chunk_len & 1;
chunk_len>>=1;
}
if(fill) // fill chain
memset(dst, *src++, chunk_len);
else // copy chain
{
memcpy(dst, src, chunk_len);
src+=chunk_len;
}
dst+=chunk_len;
col+=chunk_len;
// final hole, could be neglated at the end of the row
col += *src;
dst += *src++;
}
}
tga.width=frame.width;
tga.height=frame.height;
write(ouf, &tga, sizeof(tga));
write(ouf, palette, sizeof(palette));
write(ouf, sprite_data, sprite_data_len);
delete[] sprite_data;
close(ouf);
}
delete[] res;
return 0;
}