Jump to content

(PC) Pickup Express .gti raw textures


Go to solution Solved by ikskoks,

Recommended Posts

  • Solution
Posted

Seems like it's a container for multiple images.
In this sample, first one is 16-bit, but I'm not sure about the pixel format. Second one is 32-bit RGBA.

obraz.png.ea4d9680add30dc26df74613463e5336.png

obraz.thumb.png.25bd0183211a65f441de1a20b50ecb9c.png

File format looks like this:

 

// header
4 bytes (char) - signature // "GtIm"
4 bytes (uint32) - unknown  // 4
4 bytes (char) - chunk signature  // "CRC0"
4 bytes (uint32) - chunk size?  // 4
4 bytes (uint32) - CRC32 value?


// for each image (28-bytes header + x-bytes data)
   4 bytes (char) - chunk signature  // "Imag"
   4 bytes (uint32) - chunk size?
   4 bytes (uint32) - unknown  // 4 or 8
   4 bytes (uint32) - image width
   4 bytes (uint32) - image height
   4 bytes (uint32) - number of palette entries
   4 bytes (uint32) - unknown  // 1
   x bytes - palette data
   x bytes - image data


It could be repacked probably with a little tinkering, but you would need to recalculate CRC checksum for new data (or write a tool that does it automatically).

  • Like 1
Posted (edited)

The image at 0x430 (1072) is 16-bpp, 256x120, {i8,a8}, with the palette at 0x30 holding 256-entries, 32-bpp, {b8,g8,r8,a8}.

image.png.9dcfe7f1cba12a57df177e6c8177d89b.png

union ElementPI8A8
{
    struct
    {
        uint8_t pi; // Palette index
        uint8_t a;
    };
    uint8_t ui8[2];
    uint16_t ui16;
};

union ElementB8G8R8A8
{
    struct
    {
        uint8_t b;
        uint8_t g;
        uint8_t r;
        uint8_t a;
    };
    uint8_t ui8[4];
    uint32_t ui32;
};

...
        for (uint32_t i = 0; i < tilePixels; ++i)
        {
            auto s = source[i]; // Read {i8,a8}.
            auto c = palette[s.pi]; // Read {b8,g8,r8,a8} color entry.
            if (s.a < 255) // Scale palette entry by alpha.
            {
                c.a = c.a * s.a / 255;
                c.b = c.b * s.a / 255;
                c.g = c.g * s.a / 255;
                c.r = c.r * s.a / 255;
            }
            dest[i].ui32 = c.ui32; // Write {b8,g8,r8,a8} truecolor result.
        }

 

 

Edited by piken
  • Like 1
Posted

🤔 The shadow doesn't look right. Fixed:

image.png.2d73d0fe8cb0a77c0020b20246a8135b.png

Notice two of the palette entries have alpha = 0.

image.png.5fb0a5de48b77be81cf4cd1854244ef0.png

So we could prefer the alpha from the pi8a8 pixel over the palette's alpha when 0, and this updated logic looks correct per above...

            if (c.a == 0)
            {
                c.a = s.a; // Replace the alpha entirely, ignoring the palette.
                c.r = c.r * s.a / 255;
                c.g = c.g * s.a / 255;
                c.b = c.b * s.a / 255;
            }
            else if (s.a < 255)
            {
                c.a = c.a * s.a / 255; // Scale the alpha accordingly.
                c.r = c.r * s.a / 255;
                c.g = c.g * s.a / 255;
                c.b = c.b * s.a / 255;
            }

...but now I'm thinking the game's blending logic might simply discard the palette's alpha as ignorable b8g8r8x8 and use the i8sa8's alpha directly (blended using straight alpha), meaning more of a `pal_pi8sa8_b8g8r8x8` format:

        for (uint32_t i = 0; i < totalPixels; ++i)
        {
            auto s = sourceArray[i];
            auto c = paletteArray[s.i];
            c.a = s.a; // Use the pixel alpha mask as straight alpha.
            destArray[i].ui32 = c.ui32;
        }

That simplifies the code some. Maybe there exists other games out there which still blend the palette alpha with the pixel mask (a `pal_pi8pa8_b8g8r8pa8` format), but I don't know which (it just seemed like the logical thing to do at first, but evidently not based on the shadow). For this particular image, either approach above looks the same.

💭 Naming-wise, I probably shouldn't have called it I8A8 because that could be ambiguously confused with formats on the N64 and Wii where `I` means `grayscale intensity`, whereas `pi` would be unambiguously palette index 🤷.

gray8ap8:{grayUnorm8 alphaPremulUnorm8 notes:"N64 texture. https://github.com/queueRAM/Texture64/blob/master/Texture64/N64Graphics.cs#L64"}
ap8gray8:{alphaPremulUnorm8 grayUnorm8 notes:"Wii texture. Presuming premultiplied. http://wiki.tockdom.com/wiki/Image_Formats"}
7 hours ago, ikskoks said:

Thanks for research piken.

Sleuthing is fun 👍.

  • Like 1

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...