Exemplo n.º 1
0
        /// <summary>
        ///     Loads a Dragon Quest VII image.
        /// </summary>
        /// <param name="data">The DMP image data</param>
        /// <returns>The image as a texture</returns>
        public static RenderBase.OTexture load(Stream data)
        {
            BinaryReader input    = new BinaryReader(data);
            string       dmpMagic = IOUtils.readString(input, 0, 3);

            if (dmpMagic != "DMP")
            {
                throw new Exception("DMP: Invalid or corrupted file!");
            }

            string format     = IOUtils.readString(input, 4, 4);
            int    width      = input.ReadUInt16();
            int    height     = input.ReadUInt16();
            int    pow2Width  = input.ReadUInt16();
            int    pow2Height = input.ReadUInt16();

            byte[] buffer = new byte[data.Length - 0x10];
            data.Read(buffer, 0, buffer.Length);
            data.Close();

            Bitmap bmp = null;

            switch (format)
            {
            case "8888": bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.rgba8); break;
            }

            Bitmap   newBmp = new Bitmap(width, height);
            Graphics gfx    = Graphics.FromImage(newBmp);

            gfx.DrawImage(bmp, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel);
            gfx.Dispose();

            return(new RenderBase.OTexture(newBmp, "texture"));
        }
Exemplo n.º 2
0
        public static RenderBase.OTexture loadTexture(string fileName)
        {
            if (File.Exists(fileName))
            {
                Serialization.SERI tex = Serialization.getSERI(fileName);

                int    width           = tex.getIntegerParameter("w");
                int    height          = tex.getIntegerParameter("h");
                int    mipmap          = tex.getIntegerParameter("mipmap");
                int    format          = tex.getIntegerParameter("format");
                string textureName     = tex.getStringParameter("tex");
                string fullTextureName = Path.Combine(Path.GetDirectoryName(fileName), textureName);

                if (File.Exists(fullTextureName))
                {
                    RenderBase.OTextureFormat fmt = RenderBase.OTextureFormat.dontCare;
                    switch (format)
                    {
                    case 0: fmt = RenderBase.OTextureFormat.l4; break;

                    case 1: fmt = RenderBase.OTextureFormat.l8; break;

                    case 7: fmt = RenderBase.OTextureFormat.rgb565; break;

                    case 8: fmt = RenderBase.OTextureFormat.rgba5551; break;

                    case 9: fmt = RenderBase.OTextureFormat.rgba4; break;

                    case 0xa: fmt = RenderBase.OTextureFormat.rgba8; break;

                    case 0xb: fmt = RenderBase.OTextureFormat.rgb8; break;

                    case 0xc: fmt = RenderBase.OTextureFormat.etc1; break;

                    case 0xd: fmt = RenderBase.OTextureFormat.etc1a4; break;

                    default: Debug.WriteLine("NLP Model: Unknown Texture format 0x" + format.ToString("X8")); break;
                    }

                    string name   = Path.GetFileNameWithoutExtension(textureName);
                    byte[] buffer = File.ReadAllBytes(fullTextureName);
                    return(new RenderBase.OTexture(TextureCodec.decode(buffer, width, height, fmt), name));
                }
            }

            return(null);
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Loads a Fantasy Life ZTEX texture from a Stream.
        /// </summary>
        /// <param name="data">The Stream with the data</param>
        /// <returns>The list of textures</returns>
        public static List <RenderBase.OTexture> load(Stream data)
        {
            List <RenderBase.OTexture> textures = new List <RenderBase.OTexture>();

            BinaryReader input = new BinaryReader(data);

            string ztexMagic    = IOUtils.readString(input, 0, 4);
            ushort textureCount = input.ReadUInt16();

            input.ReadUInt16();
            input.ReadUInt32();

            List <textureEntry> entries = new List <textureEntry>();

            for (int i = 0; i < textureCount; i++)
            {
                textureEntry entry = new textureEntry();

                entry.name = IOUtils.readString(input, (uint)(0xc + (i * 0x58)));
                data.Seek(0xc + (i * 0x58) + 0x40, SeekOrigin.Begin);

                input.ReadUInt32();
                entry.offset = input.ReadUInt32();
                input.ReadUInt32();
                entry.length = input.ReadUInt32();
                entry.width  = input.ReadUInt16();
                entry.height = input.ReadUInt16();
                input.ReadByte();
                entry.format = input.ReadByte();
                input.ReadUInt16();

                entries.Add(entry);
            }

            foreach (textureEntry entry in entries)
            {
                data.Seek(entry.offset, SeekOrigin.Begin);
                byte[] buffer = new byte[entry.length];
                data.Read(buffer, 0, buffer.Length);

                Bitmap bmp = null;
                switch (entry.format)
                {
                case 1: bmp = TextureCodec.decode(buffer, entry.width, entry.height, RenderBase.OTextureFormat.rgb565); break;

                case 5: bmp = TextureCodec.decode(buffer, entry.width, entry.height, RenderBase.OTextureFormat.rgba4); break;

                case 9: bmp = TextureCodec.decode(buffer, entry.width, entry.height, RenderBase.OTextureFormat.rgba8); break;

                case 0x18: bmp = TextureCodec.decode(buffer, entry.width, entry.height, RenderBase.OTextureFormat.etc1); break;

                case 0x19: bmp = TextureCodec.decode(buffer, entry.width, entry.height, RenderBase.OTextureFormat.etc1a4); break;
                }

                textures.Add(new RenderBase.OTexture(bmp, entry.name));
            }

            data.Close();

            return(textures);
        }
Exemplo n.º 4
0
        private loadedTexture loadPKM(FileStream data, BinaryReader input)
        {
            loadedTexture tex;

            tex.modified = false;
            long descAddress2 = data.Position;

            data.Seek(descAddress2 + 0x18, SeekOrigin.Begin);
            int texLength = input.ReadInt32();

            data.Seek(descAddress2 + 0x28, SeekOrigin.Begin);
            string textureName = IOUtils.readStringWithLength(input, 0x40);

            data.Seek(descAddress2 + 0x68, SeekOrigin.Begin);
            ushort width      = input.ReadUInt16();
            ushort height     = input.ReadUInt16();
            ushort texFormat  = input.ReadUInt16();
            ushort texMipMaps = input.ReadUInt16();

            data.Seek(0x10, SeekOrigin.Current);
            tex.offset = (uint)data.Position;
            byte[] texBuffer = input.ReadBytes(texLength);

            RenderBase.OTextureFormat fmt = RenderBase.OTextureFormat.dontCare;

            switch (texFormat)
            {
            case 0x2: fmt = RenderBase.OTextureFormat.rgb565; break;

            case 0x3: fmt = RenderBase.OTextureFormat.rgb8; break;

            case 0x4: fmt = RenderBase.OTextureFormat.rgba8; break;

            case 0x17: fmt = RenderBase.OTextureFormat.rgba5551; break;

            case 0x23: fmt = RenderBase.OTextureFormat.la8; break;

            case 0x24: fmt = RenderBase.OTextureFormat.hilo8; break;

            case 0x25: fmt = RenderBase.OTextureFormat.l8; break;

            case 0x26: fmt = RenderBase.OTextureFormat.a8; break;

            case 0x27: fmt = RenderBase.OTextureFormat.la4; break;

            case 0x28: fmt = RenderBase.OTextureFormat.l4; break;

            case 0x29: fmt = RenderBase.OTextureFormat.a4; break;

            case 0x2a: fmt = RenderBase.OTextureFormat.etc1; break;

            case 0x2b: fmt = RenderBase.OTextureFormat.etc1a4; break;
            }

            Bitmap texture = TextureCodec.decode(texBuffer, width, height, fmt);

            tex.texture              = new RenderBase.OTexture(texture, textureName);
            tex.type                 = fmt;
            tex.gpuCommandsOffset    = 0;
            tex.gpuCommandsWordCount = 0;
            tex.length               = texLength;
            return(tex);
        }
Exemplo n.º 5
0
        private bool open(string fileName)
        {
            using (FileStream data = new FileStream(fileName, FileMode.Open))
            {
                BinaryReader input = new BinaryReader(data);

                if (peek(input) == 0x00010000)
                {
                    currentFile = fileName;
                    bch         = new loadedBCH();
                    bch.isBCH   = false;
                    bch.mips.Add(new MIPlayer());
                    packPNK(data, input, bch);
                }
                if (peek(input) == 0x15041213)
                {
                    currentFile = fileName;
                    bch         = new loadedBCH();
                    bch.isBCH   = false;
                    bch.mips.Add(new MIPlayer());
                    bch.mips[0].textures.Add(loadPKM(data, input));
                }
                string magic2b = getMagic(input, 2);
                if (magic2b == "PC" || magic2b == "CM")
                {
                    bch         = new loadedBCH();
                    bch.isBCH   = false;
                    currentFile = fileName;
                    data.Seek(2, SeekOrigin.Current);
                    ushort numEntrys = input.ReadUInt16();
                    for (int i = 0; i < (int)numEntrys; i++)
                    {
                        data.Seek(4 + (i * 4), SeekOrigin.Begin);
                        uint offset = input.ReadUInt32();
                        uint end    = input.ReadUInt32();
                        uint lenth  = end - offset;
                        long rtn    = data.Position;
                        data.Seek(offset, SeekOrigin.Begin);
                        if (magic2b == "CM" & i == 0)
                        {
                            packPNK(data, input, bch);
                        }
                        if (lenth > 4)
                        {
                            if (magic2b == "PC")
                            {
                                if (peek(input) == 0x15041213)
                                {
                                    bch.mips[0].textures.Add(loadPKM(data, input));
                                }
                            }
                        }
                    }
                }
                string magic = IOUtils.readString(input, 0);
                if (magic == "BCH")
                {
                    currentFile = fileName;
                    data.Seek(4, SeekOrigin.Current);
                    byte   backwardCompatibility = input.ReadByte();
                    byte   forwardCompatibility  = input.ReadByte();
                    ushort version = input.ReadUInt16();

                    uint mainHeaderOffset      = input.ReadUInt32();
                    uint stringTableOffset     = input.ReadUInt32();
                    uint gpuCommandsOffset     = input.ReadUInt32();
                    uint dataOffset            = input.ReadUInt32();
                    uint dataExtendedOffset    = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0;
                    uint relocationTableOffset = input.ReadUInt32();

                    uint mainHeaderLength      = input.ReadUInt32();
                    uint stringTableLength     = input.ReadUInt32();
                    uint gpuCommandsLength     = input.ReadUInt32();
                    uint dataLength            = input.ReadUInt32();
                    uint dataExtendedLength    = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0;
                    uint relocationTableLength = input.ReadUInt32();

                    data.Seek(mainHeaderOffset, SeekOrigin.Begin);
                    uint modelsPointerTableOffset  = input.ReadUInt32() + mainHeaderOffset;
                    uint modelsPointerTableEntries = input.ReadUInt32();

                    data.Seek(mainHeaderOffset + 0x24, SeekOrigin.Begin);
                    uint texturesPointerTableOffset  = input.ReadUInt32() + mainHeaderOffset;
                    uint texturesPointerTableEntries = input.ReadUInt32();

                    bch       = new loadedBCH();
                    bch.isBCH = true;
                    for (int i = 0; i < 6; i++)
                    {
                        bch.mips.Add(new MIPlayer());
                    }
                    MipSelect.Enabled = true;

                    //Textures
                    for (int index = 0; index < texturesPointerTableEntries; index++)
                    {
                        data.Seek(texturesPointerTableOffset + (index * 4), SeekOrigin.Begin);
                        data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin);

                        loadedTexture tex;
                        tex.modified             = false;
                        tex.gpuCommandsOffset    = input.ReadUInt32() + gpuCommandsOffset;
                        tex.gpuCommandsWordCount = input.ReadUInt32();
                        data.Seek(0x14, SeekOrigin.Current);
                        uint   textureNameOffset = input.ReadUInt32();
                        string textureName       = IOUtils.readString(input, textureNameOffset + stringTableOffset);

                        data.Seek(tex.gpuCommandsOffset, SeekOrigin.Begin);
                        PICACommandReader textureCommands = new PICACommandReader(data, tex.gpuCommandsWordCount);

                        tex.offset = textureCommands.getTexUnit0Address() + dataOffset;
                        RenderBase.OTextureFormat fmt = textureCommands.getTexUnit0Format();
                        Size textureSize = textureCommands.getTexUnit0Size();
                        tex.type = fmt;

                        int OGW = textureSize.Width;
                        int OGH = textureSize.Height;
                        for (int i = 0; i < 6; i++)
                        {
                            textureSize.Width  = OGW / Convert.ToInt32(Math.Pow(2, i));
                            textureSize.Height = OGH / Convert.ToInt32(Math.Pow(2, i));
                            tex.length         = returnSize(fmt, textureSize.Width, textureSize.Height);

                            if (textureSize.Height >= 8 & textureSize.Width >= 8)
                            {
                                data.Seek(tex.offset, SeekOrigin.Begin);
                                byte[] buffer = new byte[tex.length];

                                //data.Seek(tex.length + returnSize(fmt, textureSize.Width / 2, textureSize.Height / 2), SeekOrigin.Current);
                                tex.offset = (uint)data.Position;
                                input.Read(buffer, 0, tex.length);
                                Bitmap texture = TextureCodec.decode(
                                    buffer,
                                    textureSize.Width,
                                    textureSize.Height,
                                    fmt);

                                tex.texture = new RenderBase.OTexture(texture, textureName);

                                bch.mips[i].textures.Add(tex);
                                tex.offset = (uint)data.Position;
                            }
                        }
                    }

                    bch.mainHeaderOffset      = mainHeaderOffset;
                    bch.gpuCommandsOffset     = gpuCommandsOffset;
                    bch.dataOffset            = dataOffset;
                    bch.relocationTableOffset = relocationTableOffset;
                    bch.relocationTableLength = relocationTableLength;
                }
                else if (magic == "CTPK\u0001")
                {
                    currentFile = fileName;
                    data.Seek(4, SeekOrigin.Current);
                    ushort ver                  = input.ReadUInt16();
                    ushort numTexture           = input.ReadUInt16();
                    uint   TextureSectionOffset = input.ReadUInt32();
                    uint   TextureSectionSize   = input.ReadUInt32();
                    uint   HashSectionOffset    = input.ReadUInt32();
                    uint   TextureInfoSection   = input.ReadUInt32();

                    bch       = new loadedBCH();
                    bch.isBCH = false;
                    bch.mips.Add(new MIPlayer());
                    for (int i = 0; i < numTexture; i++)
                    {
                        data.Seek(0x20 * (i + 1), SeekOrigin.Begin);
                        loadedTexture tex;
                        tex.modified          = false;
                        tex.gpuCommandsOffset = (uint)(0x20 * (i + 1));
                        uint   textureNameOffset = input.ReadUInt32();
                        string textureName       = IOUtils.readString(input, textureNameOffset);
                        tex.length = input.ReadInt32();
                        tex.offset = input.ReadUInt32() + TextureSectionOffset;
                        tex.type   = (RenderBase.OTextureFormat)input.ReadUInt32();
                        ushort Width  = input.ReadUInt16();
                        ushort Height = input.ReadUInt16();
                        data.Seek(tex.offset, SeekOrigin.Begin);
                        byte[] buffer = new byte[tex.length];

                        input.Read(buffer, 0, buffer.Length);
                        Bitmap texture = TextureCodec.decode(
                            buffer,
                            Width,
                            Height,
                            tex.type);

                        tex.texture = new RenderBase.OTexture(texture, textureName);

                        tex.gpuCommandsWordCount = 0;

                        bch.mips[0].textures.Add(tex);
                    }
                }
            }

            updateTexturesList();
            return(true);
        }
Exemplo n.º 6
0
        /// <summary>
        ///     Loads a Binary Citra Layout Image from a Stream.
        /// </summary>
        /// <param name="data">The Stream with the data</param>
        /// <returns>The image as a texture</returns>
        public static RenderBase.OTexture load(Stream data)
        {
            BinaryReader input = new BinaryReader(data);

            data.Seek(-0x28, SeekOrigin.End);

            //Note: Stella Glow uses Little Endian BFLIMs, so please don't check the magic ;)
            string climMagic        = IOUtils.readStringWithLength(input, 4);
            ushort endian           = input.ReadUInt16();
            uint   climHeaderLength = input.ReadUInt32();

            input.ReadUInt16();
            uint fileLength = input.ReadUInt32();

            input.ReadUInt32();

            string imagMagic        = IOUtils.readStringWithLength(input, 4);
            uint   imagHeaderLength = input.ReadUInt32();
            ushort width            = input.ReadUInt16();
            ushort height           = input.ReadUInt16();
            uint   format           = input.ReadUInt32();
            uint   length           = input.ReadUInt32();

            if (climMagic == "FLIM")
            {
                format = (format >> 16) & 0xf;
            }

            data.Seek(-(length + 0x28), SeekOrigin.End);
            byte[] buffer = new byte[length];
            data.Read(buffer, 0, buffer.Length);
            data.Close();

            int pow2Width  = (int)(Math.Pow(2, Math.Ceiling(Math.Log(width) / Math.Log(2))));
            int pow2Height = (int)(Math.Pow(2, Math.Ceiling(Math.Log(height) / Math.Log(2))));

            Bitmap bmp = null;

            switch (format)
            {
            case 0: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.l8); break;

            case 1: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.a8); break;

            case 2: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.la4); break;

            case 3: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.la8); break;

            case 4: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.hilo8); break;

            case 5: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.rgb565); break;

            case 6: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.rgb8); break;

            case 7: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.rgba5551); break;

            case 8: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.rgba4); break;

            case 9: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.rgba8); break;

            case 0xa: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.etc1); break;

            case 0xb: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.etc1a4); break;

            case 0xc: bmp = TextureCodec.decode(buffer, pow2Width, pow2Height, RenderBase.OTextureFormat.l4); break;
            }

            Bitmap   newBmp = new Bitmap(width, height);
            Graphics gfx    = Graphics.FromImage(newBmp);

            gfx.DrawImage(bmp, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel);
            gfx.Dispose();

            return(new RenderBase.OTexture(newBmp, "texture"));
        }
Exemplo n.º 7
0
        /// <summary>
        ///     Loads a Game freak texture.
        /// </summary>
        /// <param name="data">The texture data</param>
        /// <returns>The image as a texture</returns>
        public static Ohana3DS_Transfigured.Ohana.RenderBase.OTexture load(Stream data, bool keepOpen = false)
        {
            BinaryReader input       = new BinaryReader(data);
            long         descAddress = data.Position;

            data.Seek(8, SeekOrigin.Current);
            if (Ohana3DS_Transfigured.Ohana.IOUtils.readStringWithLength(input, 7) != "texture")
            {
                return(null);
            }

            data.Seek(descAddress + 0x18, SeekOrigin.Begin);
            int texLength = input.ReadInt32();

            data.Seek(descAddress + 0x28, SeekOrigin.Begin);
            string texName = IOUtils.readStringWithLength(input, 0x40);

            data.Seek(descAddress + 0x68, SeekOrigin.Begin);
            ushort width      = input.ReadUInt16();
            ushort height     = input.ReadUInt16();
            ushort texFormat  = input.ReadUInt16();
            ushort texMipMaps = input.ReadUInt16();

            data.Seek(0x10, SeekOrigin.Current);
            byte[] texBuffer = input.ReadBytes(texLength);

            RenderBase.OTextureFormat fmt = RenderBase.OTextureFormat.dontCare;

            switch (texFormat)
            {
            case 0x2: fmt = RenderBase.OTextureFormat.rgb565; break;

            case 0x3: fmt = RenderBase.OTextureFormat.rgb8; break;

            case 0x4: fmt = RenderBase.OTextureFormat.rgba8; break;

            case 0x16: fmt = RenderBase.OTextureFormat.rgba4; break;

            case 0x17: fmt = RenderBase.OTextureFormat.rgba5551; break;

            case 0x23: fmt = RenderBase.OTextureFormat.la8; break;

            case 0x24: fmt = RenderBase.OTextureFormat.hilo8; break;

            case 0x25: fmt = RenderBase.OTextureFormat.l8; break;

            case 0x26: fmt = RenderBase.OTextureFormat.a8; break;

            case 0x27: fmt = RenderBase.OTextureFormat.la4; break;

            case 0x28: fmt = RenderBase.OTextureFormat.l4; break;

            case 0x29: fmt = RenderBase.OTextureFormat.a4; break;

            case 0x2a: fmt = RenderBase.OTextureFormat.etc1; break;

            case 0x2b: fmt = RenderBase.OTextureFormat.etc1a4; break;

            default: Debug.WriteLine("Unk tex fmt " + texFormat.ToString("X4") + " @ " + texName); break;
            }

            Bitmap tex = TextureCodec.decode(texBuffer, width, height, fmt);

            if (!keepOpen)
            {
                data.Close();
            }

            return(new RenderBase.OTexture(tex, texName));
        }
Exemplo n.º 8
0
        private bool open(string fileName)
        {
            using (FileStream data = new FileStream(fileName, FileMode.Open))
            {
                BinaryReader input = new BinaryReader(data);

                string magic = IOUtils.readString(input, 0);
                if (magic != "BCH")
                {
                    return(false);
                }
                currentFile = fileName;
                data.Seek(4, SeekOrigin.Current);
                byte   backwardCompatibility = input.ReadByte();
                byte   forwardCompatibility  = input.ReadByte();
                ushort version = input.ReadUInt16();

                uint mainHeaderOffset      = input.ReadUInt32();
                uint stringTableOffset     = input.ReadUInt32();
                uint gpuCommandsOffset     = input.ReadUInt32();
                uint dataOffset            = input.ReadUInt32();
                uint dataExtendedOffset    = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0;
                uint relocationTableOffset = input.ReadUInt32();

                uint mainHeaderLength      = input.ReadUInt32();
                uint stringTableLength     = input.ReadUInt32();
                uint gpuCommandsLength     = input.ReadUInt32();
                uint dataLength            = input.ReadUInt32();
                uint dataExtendedLength    = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0;
                uint relocationTableLength = input.ReadUInt32();

                data.Seek(mainHeaderOffset, SeekOrigin.Begin);
                uint modelsPointerTableOffset  = input.ReadUInt32() + mainHeaderOffset;
                uint modelsPointerTableEntries = input.ReadUInt32();

                data.Seek(mainHeaderOffset + 0x24, SeekOrigin.Begin);
                uint texturesPointerTableOffset  = input.ReadUInt32() + mainHeaderOffset;
                uint texturesPointerTableEntries = input.ReadUInt32();

                bch = new loadedBCH();

                //Textures
                for (int index = 0; index < texturesPointerTableEntries; index++)
                {
                    data.Seek(texturesPointerTableOffset + (index * 4), SeekOrigin.Begin);
                    data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin);

                    loadedTexture tex;
                    tex.modified             = false;
                    tex.gpuCommandsOffset    = input.ReadUInt32() + gpuCommandsOffset;
                    tex.gpuCommandsWordCount = input.ReadUInt32();
                    data.Seek(0x14, SeekOrigin.Current);
                    uint   textureNameOffset = input.ReadUInt32();
                    string textureName       = IOUtils.readString(input, textureNameOffset + stringTableOffset);

                    data.Seek(tex.gpuCommandsOffset, SeekOrigin.Begin);
                    PICACommandReader textureCommands = new PICACommandReader(data, tex.gpuCommandsWordCount);

                    tex.offset = textureCommands.getTexUnit0Address() + dataOffset;
                    RenderBase.OTextureFormat fmt = textureCommands.getTexUnit0Format();
                    Size textureSize = textureCommands.getTexUnit0Size();
                    switch (fmt)
                    {
                    case RenderBase.OTextureFormat.rgba8: tex.length = (textureSize.Width * textureSize.Height) * 4; break;

                    case RenderBase.OTextureFormat.rgb8: tex.length = (textureSize.Width * textureSize.Height) * 3; break;

                    case RenderBase.OTextureFormat.rgba5551: tex.length = (textureSize.Width * textureSize.Height) * 2; break;

                    case RenderBase.OTextureFormat.rgb565: tex.length = (textureSize.Width * textureSize.Height) * 2; break;

                    case RenderBase.OTextureFormat.rgba4: tex.length = (textureSize.Width * textureSize.Height) * 2; break;

                    case RenderBase.OTextureFormat.la8: tex.length = (textureSize.Width * textureSize.Height) * 2; break;

                    case RenderBase.OTextureFormat.hilo8: tex.length = (textureSize.Width * textureSize.Height) * 2; break;

                    case RenderBase.OTextureFormat.l8: tex.length = textureSize.Width * textureSize.Height; break;

                    case RenderBase.OTextureFormat.a8: tex.length = textureSize.Width * textureSize.Height; break;

                    case RenderBase.OTextureFormat.la4: tex.length = textureSize.Width * textureSize.Height; break;

                    case RenderBase.OTextureFormat.l4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break;

                    case RenderBase.OTextureFormat.a4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break;

                    case RenderBase.OTextureFormat.etc1: tex.length = (textureSize.Width * textureSize.Height) >> 1; break;

                    case RenderBase.OTextureFormat.etc1a4: tex.length = textureSize.Width * textureSize.Height; break;

                    default: throw new Exception("OBCHTextureReplacer: Invalid texture format on BCH!");
                    }

                    while ((tex.length & 0x7f) > 0)
                    {
                        tex.length++;
                    }

                    data.Seek(tex.offset, SeekOrigin.Begin);
                    byte[] buffer = new byte[textureSize.Width * textureSize.Height * 4];
                    input.Read(buffer, 0, buffer.Length);
                    Bitmap texture = TextureCodec.decode(
                        buffer,
                        textureSize.Width,
                        textureSize.Height,
                        fmt);

                    tex.texture = new RenderBase.OTexture(texture, textureName);

                    bch.textures.Add(tex);
                }

                //Materials
                for (int mdlIndex = 0; mdlIndex < modelsPointerTableEntries; mdlIndex++)
                {
                    data.Seek(modelsPointerTableOffset + (mdlIndex * 4), SeekOrigin.Begin);
                    data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin);
                    data.Seek(0x34, SeekOrigin.Current);

                    uint materialsTableOffset  = input.ReadUInt32() + mainHeaderOffset;
                    uint materialsTableEntries = input.ReadUInt32();

                    for (int index = 0; index < materialsTableEntries; index++)
                    {
                        if (backwardCompatibility < 0x21)
                        {
                            data.Seek(materialsTableOffset + (index * 0x58), SeekOrigin.Begin);
                        }
                        else
                        {
                            data.Seek(materialsTableOffset + (index * 0x2c), SeekOrigin.Begin);
                        }

                        loadedMaterial mat;

                        data.Seek(0x10, SeekOrigin.Current);
                        mat.gpuCommandsOffset    = input.ReadUInt32() + gpuCommandsOffset;
                        mat.gpuCommandsWordCount = input.ReadUInt32();

                        if (backwardCompatibility < 0x21)
                        {
                            data.Seek(0x30, SeekOrigin.Current);
                        }
                        else
                        {
                            data.Seek(4, SeekOrigin.Current);
                        }

                        uint texture0Offset = input.ReadUInt32() + stringTableOffset;
                        uint texture1Offset = input.ReadUInt32() + stringTableOffset;
                        uint texture2Offset = input.ReadUInt32() + stringTableOffset;

                        mat.texture0 = IOUtils.readString(input, texture0Offset);
                        mat.texture1 = IOUtils.readString(input, texture1Offset);
                        mat.texture2 = IOUtils.readString(input, texture2Offset);

                        bch.materials.Add(mat);
                    }
                }

                bch.mainHeaderOffset      = mainHeaderOffset;
                bch.gpuCommandsOffset     = gpuCommandsOffset;
                bch.dataOffset            = dataOffset;
                bch.relocationTableOffset = relocationTableOffset;
                bch.relocationTableLength = relocationTableLength;
            }

            updateTexturesList();
            return(true);
        }