Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
converting Crusader ingame sprites into *.tga files
05-14-2007, 08:43 PM, (This post was last modified: 05-15-2007, 04:35 AM by Cyberion.)
#1
converting Crusader ingame sprites into *.tga files
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 Big Grin
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;
}
"Time is a great teacher, but unfortunately it kills all its pupils." - Hector Berlioz
Reply
05-15-2007, 04:35 AM,
#2
Re: converting Crusader ingame sprites into *.tga files
ok i have translated the russian comments into english ones. I hope I did it right Big Grin
"Time is a great teacher, but unfortunately it kills all its pupils." - Hector Berlioz
Reply
05-15-2007, 05:12 AM,
#3
Re: converting Crusader ingame sprites into *.tga files
Cool !

I don't remember though where were these sprites located in Crusader.
Nice C code Smile

If I remember right no Hope uses the same sprites, no ? Maybe you could try it out for it.
Reply
05-15-2007, 11:18 AM,
#4
Re: converting Crusader ingame sprites into *.tga files
Hi guys.

That's me who wrote that tga-converter. Feel free to ask some questions or help.
Reply
05-15-2007, 11:21 AM,
#5
Re: converting Crusader ingame sprites into *.tga files
nice to see you here RPGman, enjoy your stay with our growing Crusader-fan community. From my part i'll add in russian: Здарова братуха!!!  ;D
"Time is a great teacher, but unfortunately it kills all its pupils." - Hector Berlioz
Reply
05-15-2007, 12:30 PM,
#6
Re: converting Crusader ingame sprites into *.tga files
Welcome RPGman!

Maybe now you can create a codec to watch the cutscenes in Windows.  Big Grin
"First let me say welcome to the Resistance, Captain."
Reply
05-15-2007, 10:07 PM,
#7
Re: converting Crusader ingame sprites into *.tga files
does this extract them with the origin/bounding box information. In other words if I play the sprite in an animated sequence they wont 'hope' or 'bounce' around? Is there a compiled version around somewhere?
[Image: signiturema1.jpg]
Reply
05-16-2007, 06:59 AM,
#8
Re: converting Crusader ingame sprites into *.tga files
(05-15-2007, 10:07 PM)wild_qwerty link Wrote: does this extract them with the origin/bounding box information.
Is there a compiled version around somewhere?

TGA don't have fields to store such info. If you have your format, you (or I) can fix it. Sprite origin stored in CrusaderSpriteFrame struct.
I can upload compiled versions for linux and windows. Does this site has file archive, or should I do it with rapidshare?
Reply
05-16-2007, 07:27 AM,
#9
Re: converting Crusader ingame sprites into *.tga files
yes, it has, however I locked it for security reasons, better to use free uploading resources. Rapidshare should be fine, i can download it from there and host here, will be no troubles.
"Time is a great teacher, but unfortunately it kills all its pupils." - Hector Berlioz
Reply
05-16-2007, 10:15 AM,
#10
Re: converting Crusader ingame sprites into *.tga files
(05-16-2007, 06:59 AM)RPGman link Wrote: TGA don't have fields to store such info. If you have your format, you (or I) can fix it. Sprite origin stored in CrusaderSpriteFrame struct.
I can upload compiled versions for linux and windows. Does this site has file archive, or should I do it with rapidshare?

Is there some way you can add this information in a separate txt or ini file for each image? Or be able to export the images into animated GIF files? That way the offsets will be included (or is TNG one of those file formats that is animated, I'm making a wally out of myself).
[Image: signiturema1.jpg]
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)