Jump to content

Gamewave texture .zbm format


Halamix2
Go to solution Solved by piken,

Recommended Posts

Hello, I've been working a bit on reversing file formats used in a Gamewave game console and I'm stuck on image color encoding (I doubt this is RGB, might be YUV420 or something completely different):

I know mostly how the image header looks like (https://github.com/namgo/GameWaveFans/wiki/Image,-Music-formats), all data from byte 0x30 is zlib packed:

looks like either each two pixels are swapped, or somehow interconnected (maybe 4633 is just two pixels of separate 46 (4alpha and 6sth) and two connected values spread across two pixels (3+3 & 3+3?)

I've found mentions in the game binary to "4633", this looks like a correct-ish packing of 4 unknown values into each two bytes

the left most value (4xxx) looks like alpha channel data

 

Files in the archive:

.zbm is the original image file

.data is the unpacked zlib stream.  

activate_remotes_bg.png  is taken from a mpg video included with the game, so I assume this is how the .zbm image should look like.

naive_unpack.png is me just assuming the remaining fields are just storing RGB data ( ARGB4633) (code for the converter is stored at the same repo as the wiki)

activateblue.zbm should be ok for testing/finding alpha channel data

zbm_format.zip

Link to comment
Share on other sites

  • Solution

The data sample is 16bit x 720 x 480 with each pixel having fields:

struct PixelCr3Cb3Cy6a4 // nomenclature listed consistently with increasing bit field order, like PFNC and DXGI.
{
    uint3 cr;    // chromatic red (bits 0-2)
    uint3 cb;    // chromatic blue (bits 3-5)
    uint6 cy;    // luminance (bits 6-11)
    uint4 alpha; // 0xF = opaque (bits 12-15)
}

Note because it's MIPS, there will be some endianness issues, needing to unravel 8 bits per every 32 bits (and oddly not the usual byte swapped 8 bits per 16 bit element), or else you get columns that look swapped. So if your memory stream had {0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04}, reorder to -> {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}.

Some quick and dirty code for color space conversion:

    auto luminance = uint8_t(((sourceWord >>  6) & 0x3F) << 2);
    auto cr        = uint8_t(((sourceWord >>  0) & 0x07) << 5); // simple left shift, no rescale
    auto cb        = uint8_t(((sourceWord >>  3) & 0x07) << 5);
    auto alpha     = uint8_t(((sourceWord >> 12) & 0x0F) * 17);

    // Convert YCbCr to RGB
    ElementB8G8R8A8 adjustedColor =
    {
        .b = uint8_t(std::clamp(y + ((113 * cb          ) / 64), 0, 255)),
        .g = uint8_t(std::clamp(y - (( 11 * cb + 23 * cr) / 32), 0, 255)),
        .r = uint8_t(std::clamp(y + ((           45 * cr) / 32), 0, 255)),
        .a = alpha,
        // equivalent floating point:
        // std::clamp(1.164f * (luminance - 16) + 2.018f * (cb - 128), 0.0f, 255.0f))
        // std::clamp(1.164f * (luminance - 16) - 0.813f * (cr - 128) - 0.391f * (cb - 128), 0.0f, 255.0f))
        // std::clamp(1.164f * (luminance - 16) + 1.596f * (cr - 128), 0.0f, 255.0f))
    };

I tried using rescaling or bit replication too (mapping chromatic red 0-7 to 0-255), but simple left shifting looked more faithful to your reference image:

activate_remotes_bg.data.png

image.png.f655742bf1578bdb295e217596a37190.png

Edited by piken
Add alpha image
  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...