Beispiel #1
0
        /// <summary>
        ///     Decodes a PICA200 Texture.
        /// </summary>
        /// <param name="data">Buffer with the Texture</param>
        /// <param name="width">Width of the Texture</param>
        /// <param name="height">Height of the Texture</param>
        /// <param name="format">Pixel Format of the Texture</param>
        /// <returns></returns>
        public static Bitmap decode(byte[] data, int width, int height, RenderBase.OTextureFormat format)
        {
            byte[] output     = new byte[width * height * 4];
            long   dataOffset = 0;
            bool   toggle     = false;

            switch (format)
            {
            case RenderBase.OTextureFormat.rgba8:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + ((tY * 8 + y) * width)) * 4;

                            Buffer.BlockCopy(data, (int)dataOffset + 1, output, (int)outputOffset, 3);
                            output[outputOffset + 3] = data[dataOffset];

                            dataOffset += 4;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.rgb8:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            Buffer.BlockCopy(data, (int)dataOffset, output, (int)outputOffset, 3);
                            output[outputOffset + 3] = 0xff;

                            dataOffset += 3;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.rgba5551:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            ushort pixelData = (ushort)(data[dataOffset] | (data[dataOffset + 1] << 8));

                            byte r = (byte)(((pixelData >> 1) & 0x1f) << 3);
                            byte g = (byte)(((pixelData >> 6) & 0x1f) << 3);
                            byte b = (byte)(((pixelData >> 11) & 0x1f) << 3);
                            byte a = (byte)((pixelData & 1) * 0xff);

                            output[outputOffset]     = (byte)(r | (r >> 5));
                            output[outputOffset + 1] = (byte)(g | (g >> 5));
                            output[outputOffset + 2] = (byte)(b | (b >> 5));
                            output[outputOffset + 3] = a;

                            dataOffset += 2;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.rgb565:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            ushort pixelData = (ushort)(data[dataOffset] | (data[dataOffset + 1] << 8));

                            byte r = (byte)((pixelData & 0x1f) << 3);
                            byte g = (byte)(((pixelData >> 5) & 0x3f) << 2);
                            byte b = (byte)(((pixelData >> 11) & 0x1f) << 3);

                            output[outputOffset]     = (byte)(r | (r >> 5));
                            output[outputOffset + 1] = (byte)(g | (g >> 6));
                            output[outputOffset + 2] = (byte)(b | (b >> 5));
                            output[outputOffset + 3] = 0xff;

                            dataOffset += 2;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.rgba4:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            ushort pixelData = (ushort)(data[dataOffset] | (data[dataOffset + 1] << 8));

                            byte r = (byte)((pixelData >> 4) & 0xf);
                            byte g = (byte)((pixelData >> 8) & 0xf);
                            byte b = (byte)((pixelData >> 12) & 0xf);
                            byte a = (byte)(pixelData & 0xf);

                            output[outputOffset]     = (byte)(r | (r << 4));
                            output[outputOffset + 1] = (byte)(g | (g << 4));
                            output[outputOffset + 2] = (byte)(b | (b << 4));
                            output[outputOffset + 3] = (byte)(a | (a << 4));

                            dataOffset += 2;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.la8:
            case RenderBase.OTextureFormat.hilo8:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            output[outputOffset]     = data[dataOffset];
                            output[outputOffset + 1] = data[dataOffset];
                            output[outputOffset + 2] = data[dataOffset];
                            output[outputOffset + 3] = data[dataOffset + 1];

                            dataOffset += 2;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.l8:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            output[outputOffset]     = data[dataOffset];
                            output[outputOffset + 1] = data[dataOffset];
                            output[outputOffset + 2] = data[dataOffset];
                            output[outputOffset + 3] = 0xff;

                            dataOffset++;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.a8:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            output[outputOffset]     = 0xff;
                            output[outputOffset + 1] = 0xff;
                            output[outputOffset + 2] = 0xff;
                            output[outputOffset + 3] = data[dataOffset];

                            dataOffset++;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.la4:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            output[outputOffset]     = (byte)(data[dataOffset] >> 4);
                            output[outputOffset + 1] = (byte)(data[dataOffset] >> 4);
                            output[outputOffset + 2] = (byte)(data[dataOffset] >> 4);
                            output[outputOffset + 3] = (byte)(data[dataOffset] & 0xf);

                            dataOffset++;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.l4:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            byte c = toggle ? (byte)((data[dataOffset++] & 0xf0) >> 4) : (byte)(data[dataOffset] & 0xf);
                            toggle = !toggle;
                            c      = (byte)((c << 4) | c);
                            output[outputOffset]     = c;
                            output[outputOffset + 1] = c;
                            output[outputOffset + 2] = c;
                            output[outputOffset + 3] = 0xff;
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.a4:
                for (int tY = 0; tY < height / 8; tY++)
                {
                    for (int tX = 0; tX < width / 8; tX++)
                    {
                        for (int pixel = 0; pixel < 64; pixel++)
                        {
                            int  x            = tileOrder[pixel] % 8;
                            int  y            = (tileOrder[pixel] - x) / 8;
                            long outputOffset = ((tX * 8) + x + (((tY * 8 + y)) * width)) * 4;

                            output[outputOffset]     = 0xff;
                            output[outputOffset + 1] = 0xff;
                            output[outputOffset + 2] = 0xff;
                            byte a = toggle ? (byte)((data[dataOffset++] & 0xf0) >> 4) : (byte)(data[dataOffset] & 0xf);
                            toggle = !toggle;
                            output[outputOffset + 3] = (byte)((a << 4) | a);
                        }
                    }
                }
                break;

            case RenderBase.OTextureFormat.etc1:
            case RenderBase.OTextureFormat.etc1a4:
                byte[] decodedData = etc1Decode(data, width, height, format == RenderBase.OTextureFormat.etc1a4);
                int[]  etc1Order   = etc1Scramble(width, height);

                int i = 0;
                for (int tY = 0; tY < height / 4; tY++)
                {
                    for (int tX = 0; tX < width / 4; tX++)
                    {
                        int TX = etc1Order[i] % (width / 4);
                        int TY = (etc1Order[i] - TX) / (width / 4);
                        for (int y = 0; y < 4; y++)
                        {
                            for (int x = 0; x < 4; x++)
                            {
                                dataOffset = ((TX * 4) + x + (((TY * 4) + y) * width)) * 4;
                                long outputOffset = ((tX * 4) + x + (((tY * 4 + y)) * width)) * 4;

                                Buffer.BlockCopy(decodedData, (int)dataOffset, output, (int)outputOffset, 4);
                            }
                        }
                        i += 1;
                    }
                }

                break;
            }

            return(TextureUtils.getBitmap(output.ToArray(), width, height));
        }