Palm-Studios / sh3redux

SILENT HILL 3 Engine Remake in OpenGL and C++
GNU General Public License v3.0
158 stars 15 forks source link

Breakdown swizzled 8bpp paletted texture data #154

Open 316austin316 opened 1 year ago

316austin316 commented 1 year ago

Hello, i looked at the old blog and saw that you figured out how to unswizzle the 8bpp textures and apply the correct palette data, i am looking at the texture.cpp code and saw a sort of breakdown, but it's kind of messy. I'm working on my own sh3 texture tool and was wondering if you could explain and breakdown the textures so i can implement it in my code?

Quaker762 commented 2 months ago

Hi @316austin316

I believe the swizzle of these textures is based on the TIM2 format. You can find more information here: https://openkh.dev/common/tm2.html

This page didn't exist when I was working on this. Hopefully this helps.

316austin316 commented 2 months ago

Hi @316austin316

I believe the swizzle of these textures is based on the TIM2 format. You can find more information here: https://openkh.dev/common/tm2.html

This page didn't exist when I was working on this. Hopefully this helps.

yes i have managed to unswizzle 8bpp textures friend thank you, now i'm struggling with 4 bpp. also i have looked at your palette data code and while it worked maybe 50% of the time, i am having issues with sometimes incorrect palette. If you have any information, I would appreciate it

Quaker762 commented 2 months ago

If you have any information, I would appreciate it

Sure. This guys has some pseudocode related to unswizzling TM2 stuff, he took it from the (now defunct) Xentax wiki. I believe this is where the original implementation of this came from when it was submitted to sh3redux, however this was approaching 8 years old now.

Maybe @muddle12 can himself comment on this further.

https://github.com/muddle12/DCExtractor/blob/main/Specifications/Images/TM2.md

//Convert the TIM2Picture's palette to linear 32-bit True Color.
Color[] ConvertPicturePaletteToRGBA(TIM2Picture tPicture)
{
    //If there is no palette, return an empty palette.
    if (tPicture.paletteBytes == null || tPicture.paletteBytes.Length == 0)
        return null;

    //Otherwise, we're going to have to figure out which palette we're using based on the paletteColorSize.
    Color[] tPalette;
    if (tPicture.bitsPerPixel <= 8)
    {
        //We'll infer which palette type we're using based on the size of each individual palette entry.
        switch (tPicture.colorSize)
        {
            case 2://16 BIT LE_ABGR_1555?
                {
                    tPalette = FromBufferABGR1555(tPicture.paletteBytes, tPicture.paletteSize);
                }
                break;
            case 3://24 BIT RGB?
                {
                    tPalette = FromBufferRGB24Bit(tPicture.paletteBytes, tPicture.paletteSize);
                }
                break;
            case 4://32 BIT RGBA?
                {
                    tPalette = FromBufferRGBA32Bit(tPicture.paletteBytes, tPicture.paletteSize);
                }
                break;
            default://Invalid data.
                return null;
        }

        //If the palette is interleaved, we need to unpack that into something linear.
        if (tPicture.isLinearPalette == false)
        {
            //The TIM2 palettes always have these fixed values.
            const int nBlockCount = 2;
            const int nStripeCount = 2;
            const int nColorCount = 8;

            //Some calculations for unpacking the palette.
            int nPartCount = tPalette.Length / 32;
            int nPartStride = nColorCount * nStripeCount * nBlockCount;
            int nStripeStride = nStripeCount * nColorCount;

            //This next part was ripped wholesale from the xentax references. I couldn't tell you exactly what's going on, but it appears to work.
            //If I had to guess, TIM2 has a very particular kind of interleave using blocks instead of straight stripes.
            int i = 0;
            Color[] tUnpackedColors = new Color[tPalette.Length];
            for (int part = 0; part < nPartCount; part++)
            {
                for (int block = 0; block < nBlockCount; block++)
                {
                    for (int stripe = 0; stripe < nStripeCount; stripe++)
                    {
                        for (int color = 0; color < nColorCount; color++)
                        {
                            tUnpackedColors[i++] = tPalette[(part * nPartStride) + (block * nColorCount) + (stripe * nStripeStride) + color];
                        }
                    }
                }
            }

            //overwrite the original palette, as we don't need it anymore.
            tPalette = tUnpackedColors;
        }
    }
    return tPalette;
}