protected override TextureFormat CreateFrameForGeneralTexture(NamcoTexture texture, int frame, GenericDictionary formatSpecificData, IList <System.Drawing.Image> images, System.Drawing.Image referenceImage, int mipmapsCount)
        {
            TextureFormat segment = null;

            ushort version     = texture.FormatSpecificData.Get <ushort>(VERSION_KEY);
            byte   clutFormat  = formatSpecificData.Get <byte>(CLUTFORMAT_KEY);
            byte   depth       = formatSpecificData.Get <byte>(DEPTH_KEY);
            int    colorsCount = 1 << depth;

            int width  = images.First().Width;
            int height = images.First().Height;

            byte[] data     = formatSpecificData.Get <byte[]>(DATA_KEY);
            byte[] userData = formatSpecificData.Get <byte[]>(USERDATA_KEY);

            if (IsPaletted(clutFormat))
            {
                ColorCodec    paletteCodec;
                IndexCodec    indexCodec;
                ImageFilter   imgFilter;
                PaletteFilter palFilter;

                GetPalettedTools(version, clutFormat, depth, colorsCount, width, height, data, userData,
                                 out paletteCodec, out indexCodec, out imgFilter, out palFilter);

                var builder = new PalettedTextureFormat.Builder()
                              .SetPaletteCodec(paletteCodec)
                              .SetMipmapsCount(mipmapsCount)
                              .SetIndexCodec(indexCodec)
                              .SetImageFilter(imgFilter)
                              .SetPaletteFilter(palFilter);
                if (referenceImage != null)
                {
                    segment = builder.Build(referenceImage, images.Select(img => img.GetColorArray()).ToList());
                }
                else
                {
                    segment = builder.Build(images.First());
                }
            }
            else
            {
                ColorCodec  imageCodec;
                ImageFilter imgFilter;

                GetUnpalettedTools(version, clutFormat, depth, colorsCount, width, height, data, userData,
                                   out imageCodec, out imgFilter);

                segment = new GenericTextureFormat.Builder()
                          .SetColorCodec(imageCodec)
                          .SetMipmapsCount(mipmapsCount)
                          .SetImageFilter(imgFilter)
                          .Build(images.First());
            }

            texture.TextureFormats.Add(segment);

            return(segment);
        }
        private TextureFormat ConstructSegment(BinaryReader reader, ushort version)
        {
            ByteOrder order        = GetByteOrder();
            uint      totalSize    = reader.ReadUInt32(order);
            uint      paletteSize  = reader.ReadUInt32(order);
            uint      imageSize    = reader.ReadUInt32(order);
            uint      headerSize   = reader.ReadUInt16(order);
            int       colorsCount  = reader.ReadUInt16(order);
            byte      format       = reader.ReadByte();
            byte      mipmapsCount = reader.ReadByte();

            if (!IsSupportedFormat(format))
            {
                throw new TextureFormatException("Unsupported image format!");
            }

            byte clutFormat = reader.ReadByte();
            byte depth      = reader.ReadByte();

            int width  = reader.ReadUInt16(order);
            int height = reader.ReadUInt16(order);

            byte[] data = reader.ReadBytes(24);

            uint userDataSize = headerSize - 0x30;

            byte[] userdata = null;
            if (userDataSize > 0)
            {
                userdata = reader.ReadBytes((int)userDataSize);
            }

            int totalPixels = 0;

            for (int i = 0; i < mipmapsCount; i++)
            {
                totalPixels += ImageUtils.GetMipmapWidth(width, i) * ImageUtils.GetMipmapHeight(height, i);
            }

            int firstImageSize = mipmapsCount != 0? (int)((width * height * imageSize) / totalPixels) : 0;

            byte[] imgData = reader.ReadBytes(firstImageSize);
            //we don't need to load the mipmaps, since they can be generated as needed.
            //just skip the mipmaps
            reader.BaseStream.Position += (imageSize - firstImageSize);

            byte[] palData = reader.ReadBytes((int)paletteSize);

            TextureFormat segment = null;

            if (IsPaletted(clutFormat))
            {
                int colorSize         = GetPaletteColorSize(clutFormat);
                int numberOfPalettes  = palData.Length / (colorsCount * colorSize);
                int singlePaletteSize = palData.Length / numberOfPalettes;

                IList <byte[]> palettes = new List <byte[]>(numberOfPalettes);
                for (int i = 0; i < numberOfPalettes; i++)
                {
                    palettes.Add(palData.Skip(i * singlePaletteSize).Take(singlePaletteSize).ToArray());
                }

                PalettedTextureFormat.Builder builder = new PalettedTextureFormat.Builder();

                ColorCodec    paletteCodec;
                IndexCodec    indexCodec;
                ImageFilter   imgFilter;
                PaletteFilter palFilter;

                GetPalettedTools(version, clutFormat, depth, colorsCount, width, height, data, userdata,
                                 out paletteCodec, out indexCodec, out imgFilter, out palFilter);

                builder.SetPaletteCodec(paletteCodec)
                .SetMipmapsCount(mipmapsCount)
                .SetIndexCodec(indexCodec)
                .SetImageFilter(imgFilter)
                .SetPaletteFilter(palFilter);

                segment = builder.Build(imgData, palettes, width, height);
            }
            else
            {
                ColorCodec  imageCodec;
                ImageFilter imgFilter;
                GenericTextureFormat.Builder builder = new GenericTextureFormat.Builder();

                GetUnpalettedTools(version, clutFormat, depth, colorsCount, width, height, data, userdata,
                                   out imageCodec, out imgFilter);

                segment = builder.SetColorCodec(imageCodec)
                          .SetMipmapsCount(mipmapsCount)
                          .SetImageFilter(imgFilter)
                          .Build(imgData, width, height);
            }

            segment.FormatSpecificData.Put <byte>(CLUTFORMAT_KEY, clutFormat)
            .Put <byte>(FORMAT_KEY, format)
            .Put <byte>(DEPTH_KEY, depth)
            .Put <byte[]>(DATA_KEY, data)
            .Put <byte[]>(USERDATA_KEY, userdata);

            return(segment);
        }
        public override TextureFormat Open(System.IO.Stream formatData)
        {
            if (!IsValidFormat(formatData))
            {
                throw new TextureFormatException("Not a valid TPL Texture!");
            }

            BinaryReader reader = new BinaryReader(formatData);

            reader.BaseStream.Position += 4;

            ByteOrder order = ByteOrder.BigEndian;

            int  texturesCount    = (int)reader.ReadUInt32(order);
            uint imageTableOffset = reader.ReadUInt32(order);

            reader.BaseStream.Position = imageTableOffset;

            TPLTexture texture = new TPLTexture();

            for (int i = 0; i < texturesCount; i++)
            {
                TextureFormat segment = null;

                //image table
                uint imageHeaderOffset   = reader.ReadUInt32(order);
                uint offsetPaletteHeader = reader.ReadUInt32(order);

                long oldPos = reader.BaseStream.Position;

                reader.BaseStream.Position = imageHeaderOffset;

                int  height        = reader.ReadUInt16(order);
                int  width         = reader.ReadUInt16(order);
                uint format        = reader.ReadUInt32(order);
                uint imgDataOffset = reader.ReadUInt32(order);

                ColorCodec  colorCodec = null;
                IndexCodec  idxCodec   = null;
                ImageFilter imgFilter  = null;

                ushort entryCount    = 0;
                ushort unknown       = 0;//this might be a set of flags denoting whether the palette is internal to the tpl image or external.
                uint   paletteFormat = 0;
                uint   palDataOffset = 0;
                bool   isIndexed     = false;

                int imgDataSize = 0;
                int palDataSize = 0;

                switch (format)
                {
                case 0:     //I4
                    colorCodec  = ColorCodec.CODEC_4BITBE_I4;
                    imgFilter   = new TileFilter(4, 8, 8, width, height);
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 1:     //I8
                    colorCodec  = ColorCodec.CODEC_8BIT_I8;
                    imgFilter   = new TileFilter(8, 8, 4, width, height);
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 2:     //IA4
                    colorCodec  = ColorCodec.CODEC_8BITBE_IA4;
                    imgFilter   = new TileFilter(8, 8, 4, width, height);
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 3:     //IA8
                    colorCodec  = ColorCodec.CODEC_16BITBE_IA8;
                    imgFilter   = new TileFilter(16, 4, 4, width, height);
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 4:     //RGB565
                    colorCodec  = ColorCodec.CODEC_16BITBE_RGB565;
                    imgFilter   = new TileFilter(16, 4, 4, width, height);
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 5:     //RGB5A3
                    colorCodec  = ColorCodec.CODEC_16BITBE_RGB5A3;
                    imgFilter   = new TileFilter(16, 4, 4, width, height);
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 6:     //RGBA32 2 planes
                    colorCodec = ColorCodec.CODEC_32BIT_ARGB;
                    imgFilter  = new ImageFilterComposer {
                        new GamecubePlanarFilter(),
                        new TileFilter(32, 4, 4, width, height)
                    };
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 8:     //C4
                case 9:     //C8
                    isIndexed = true;
                    reader.BaseStream.Position = offsetPaletteHeader;

                    entryCount = reader.ReadUInt16(order);
                    unknown    = reader.ReadUInt16(order);

                    paletteFormat = reader.ReadUInt32(order);
                    palDataOffset = reader.ReadUInt32(order);

                    switch (paletteFormat)
                    {
                    case 0:
                        colorCodec = ColorCodec.CODEC_16BITBE_IA8;
                        break;

                    case 1:
                        colorCodec = ColorCodec.CODEC_16BITBE_RGB565;
                        break;

                    case 2:
                        colorCodec = ColorCodec.CODEC_16BITBE_RGB5A3;
                        break;

                    default:
                        throw new TextureFormatException("Unsupported palette format " + paletteFormat);
                    }
                    palDataSize = colorCodec.GetBytesNeededForEncode(entryCount, 1);

                    if (format == 8)
                    {
                        idxCodec  = IndexCodec.FromBitPerPixel(4, order);
                        imgFilter = new TileFilter(4, 8, 8, width, height);
                    }
                    else
                    {
                        idxCodec  = IndexCodec.FromBitPerPixel(8, order);
                        imgFilter = new TileFilter(8, 8, 4, width, height);
                    }

                    imgDataSize = idxCodec.GetBytesNeededForEncode(width, height, imgFilter);
                    break;

                case 0xA:     //C14X2
                    throw new TextureFormatException("C14X2 not implemented yet!");
                    break;

                case 0xE:     //DXT1 (aka CMPR)
                    colorCodec  = new ColorCodecDXT1Gamecube(width, height);
                    imgDataSize = colorCodec.GetBytesNeededForEncode(width, height);
                    break;

                default:
                    throw new TextureFormatException("Unsupported TPL image format " + format);
                }

                reader.BaseStream.Position = imgDataOffset;
                byte[] imgData = reader.ReadBytes(imgDataSize);

                if (isIndexed)
                {
                    reader.BaseStream.Position = palDataOffset;
                    byte[] palData = reader.ReadBytes(palDataSize);

                    PalettedTextureFormat.Builder builder = new PalettedTextureFormat.Builder();
                    segment = builder.SetIndexCodec(idxCodec)
                              .SetPaletteCodec(colorCodec)
                              .SetImageFilter(imgFilter)
                              .Build(imgData, palData, width, height);
                }
                else
                {
                    GenericTextureFormat.Builder builder = new GenericTextureFormat.Builder();
                    segment = builder.SetColorCodec(colorCodec)
                              .SetImageFilter(imgFilter)
                              .Build(imgData, width, height);
                }

                segment.FormatSpecificData.Put <uint>(FORMAT_KEY, format)
                .Put <uint>(UNKNOWN_KEY, unknown)
                .Put <uint>(PALETTEFORMAT_KEY, paletteFormat);

                texture.TextureFormats.Add(segment);

                reader.BaseStream.Position = oldPos;
            }

            return(texture);
        }