ZenHAX

Free Game Research Forum | Official QuickBMS support | twitter @zenhax | SSL HTTPS://zenhax.com
It is currently Sat Oct 20, 2018 3:52 am

All times are UTC




Post new topic  Reply to topic  [ 4 posts ] 
Author Message
PostPosted: Thu Nov 23, 2017 10:56 pm 

Joined: Thu Apr 20, 2017 12:54 pm
Posts: 3
I'm currently extrating assets from Liberation Day (1998) in order to remake it.
I'm working on extracting .DBI files, which are archives of image assets.

I've managed to extract uncompressed images as 256bit indexed bitmaps from one of these DBI files.

It seems like there are some dbi files that are compressed, though. I'm trying to guess the compression without much luck. I'd need help or tips on how to find this.

Here you can find a link to the smallest (34KBs) DBI with compressed images file:
https://drive.google.com/file/d/1kPP3qP ... sp=sharing

You can jump to 0x434 and take the first 1133 bytes; that is the compressed image data.
I learned about this by decompiling the game code, but I cannot make any sense of the code that seems to decompress. I can upload snippets from that if it's helpful.

If you want to know more about the file structure, this is what I know from the header:
  • 0x0C Width: 54
  • 0x10 Height: 56
  • 0x14 Compressed: 1
  • 0x20 256-entry palette that takes 1024bytes

And what I know from the first image in the file:
  • 0x420 (+0x00) Name: MINE001
  • 0x428 (+0x08) Width: 54
  • 0x42A (+0x0A) Height: 56
  • 0x42C (+0x0C) Size of image color buffer in bytes: 1133
  • 0x434 (+0x20) Image color buffer.

One can find images at 0x420 + i * 0x2000.

Thanks!


Top
   
PostPosted: Fri Nov 24, 2017 6:54 am 

Joined: Thu Nov 23, 2017 12:30 am
Posts: 23
At the end of the archive, at 0x00008420, you can find the directory, containing 4 entries:
"MINE000\0", Index 2
"GMINE000", Index 3
"MINE001\0", Index 0
"GMINE001", Index 1

Each of these inner files contains more than one single image, and other kind of data, like a list of terrains (index + name)
I don't know if you need all these data, so I will just show you how to decode pixels data.

At 0x00000434 (like you said), starts pixels data for the first image, and you can find 56 descriptors, one for each scan line of the image. After the descriptors, you will find a single byte with value = 0xCD, possibly used at End of Image as a check.
The structure of a line is:
Record Line
{
long lineDataLength
byte[lineDataLength - 4] lineData
}

If lineDataLength is greater than 8, you need to read pixels by repeating LinePixels records until all lineDataLength bytes are consumed

Record LinePixels
{
short length
short behavior
if (behavior == 0x0002)
byte[length] PixelsData
endif
}

An example could be handy:
08 00 00 00
lineDataLength = 0x00000008
so we read a LinePixels record:
36 00 01 00
length = 54 (the whole line for this image size)
behaviour = 0x0001 (transparent pixels)

Another example, this time with several chunks of data for a single line:
Code:
36 00 00 00    09 00 01 00    0C 00 02 00    DD 6F 8A ED 47 6C F7 57 34 5D ED 63 
            09 00 01 00    09 00 02 00    DD 5D 5D 6F B0 2F 61 37 39
            01 00 01 00    01 00 02 00    DD                               0D 00 01 00

lineDataLength = 54 (0x00000036)
read a chunk:
length = 9
behavior = 0x0001
so we add 9 transparent pixels and read the next chunk
length = 12
behavior = 0x0002
so we read 12 bytes, and write them to the output image, then read next chunk
length = 9
behavior = 0x0001
so we add another 9 transparent pixels and read the next chunk
length = 9
behavior = 0x0002
so we read 9 bytes, and write them to the output image, then read next chunk
length = 1
behavior = 0x0001
so we add another 1 transparent pixel and read the next chunk
length = 1
behavior = 0x0002
so we read 2 bytes, and write them to the output image, then read next chunk
length = 13
behavior = 0x0001
so we add another 13 transparent pixels and the line is completed, as we have read all the specified 54 bytes and the pixels count for this line is already the max

Some pseudo-code written here on the fly, not tested and not including errors check:
Code:
ReadLineOfPixels()
{
   int32 length = Data.ReadInt32();                  // Including this field
   int bytesRead = 4;
   while (bytesRead < length)
   {
      int16 amount = Data.ReadInt16();
      bytesRead += 2;
      int16 behavior = Data.ReadInt16();
      bytesRead += 2;
      if (behavior == 0x0001)
      {
         ImageOut.Write(amount, 0x00);             // Put "amount" of transparent pixels
      }
      elseif (behavior == 0x0002)
      {
         byte[] pixels = Data.ReadBytes(amount);          // Read "amount" of bytes, as indices in the palette
         bytesRead += amount;
         ImageOut.Write(pixels);
      }
      else
      {
         // Unsupported or Corrupted data; break program
      }
   }
}


Top
   
PostPosted: Fri Nov 24, 2017 8:08 am 

Joined: Thu Apr 20, 2017 12:54 pm
Posts: 3
Thanks for the info and the quick reply.

I was specially blocked by this :)

After your explanation and pseudocode I understand this is a form of RLE encoding, right?
I'm trying to understand if this a named algorithm, so I can code this with it's proper naming :)

Thanks!


Top
   
PostPosted: Fri Nov 24, 2017 8:21 am 

Joined: Thu Nov 23, 2017 12:30 am
Posts: 23
Yes, it is one of the multiple variations of RLE used in old games (the simplest one).


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 4 posts ] 

All times are UTC


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
cron
Powered by phpBB® Forum Software © phpBB Limited