public void Write(EndianBinaryWriter writer)
        {
            long start = writer.BaseStream.Position;

            writer.Write("MAT3".ToCharArray());
            writer.Write(0); // Placeholder for section offset
            writer.Write((short)m_RemapIndices.Count);
            writer.Write((short)-1);

            writer.Write(132); // Offset to material init data. Always 132

            for (int i = 0; i < 29; i++)
            {
                writer.Write(0);
            }

            bool[]        writtenCheck = new bool[m_Materials.Count];
            List <string> names        = m_MaterialNames;

            for (int i = 0; i < m_RemapIndices.Count; i++)
            {
                if (writtenCheck[m_RemapIndices[i]])
                {
                    continue;
                }
                else
                {
                    WriteMaterialInitData(writer, m_Materials[m_RemapIndices[i]]);
                    writtenCheck[m_RemapIndices[i]] = true;
                }
            }

            long curOffset = writer.BaseStream.Position;

            // Remap indices offset
            writer.Seek((int)start + 16, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            for (int i = 0; i < m_RemapIndices.Count; i++)
            {
                writer.Write((short)m_RemapIndices[i]);
            }

            curOffset = writer.BaseStream.Position;

            // Name table offset
            writer.Seek((int)start + 20, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            NameTableIO.Write(writer, names);
            StreamUtility.PadStreamWithString(writer, 8);

            curOffset = writer.BaseStream.Position;

            // Indirect texturing offset
            writer.Seek((int)start + 24, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            IndirectTexturingIO.Write(writer, m_IndirectTexBlock);

            curOffset = writer.BaseStream.Position;

            // Cull mode offset
            writer.Seek((int)start + 28, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            CullModeIO.Write(writer, m_CullModeBlock);

            curOffset = writer.BaseStream.Position;

            // Material colors offset
            writer.Seek((int)start + 32, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            ColorIO.Write(writer, m_MaterialColorBlock);

            curOffset = writer.BaseStream.Position;

            // Color channel count offset
            writer.Seek((int)start + 36, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            foreach (byte chanNum in NumColorChannelsBlock)
            {
                writer.Write(chanNum);
            }

            StreamUtility.PadStreamWithStringByOffset(writer, (int)(writer.BaseStream.Position - curOffset), 4);

            curOffset = writer.BaseStream.Position;

            // Color channel data offset
            writer.Seek((int)start + 40, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            ColorChannelIO.Write(writer, m_ChannelControlBlock);

            curOffset = writer.BaseStream.Position;

            // ambient color data offset
            writer.Seek((int)start + 44, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            ColorIO.Write(writer, m_AmbientColorBlock);

            curOffset = writer.BaseStream.Position;

            // light color data offset
            writer.Seek((int)start + 48, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            if (m_LightingColorBlock != null)
            {
                ColorIO.Write(writer, m_LightingColorBlock);
            }

            curOffset = writer.BaseStream.Position;

            // tex gen count data offset
            writer.Seek((int)start + 52, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            foreach (byte texGenCnt in NumTexGensBlock)
            {
                writer.Write(texGenCnt);
            }

            StreamUtility.PadStreamWithStringByOffset(writer, (int)(writer.BaseStream.Position - curOffset), 4);

            curOffset = writer.BaseStream.Position;

            // tex coord 1 data offset
            writer.Seek((int)start + 56, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            TexCoordGenIO.Write(writer, m_TexCoord1GenBlock);

            curOffset = writer.BaseStream.Position;

            if (m_TexCoord2GenBlock != null)
            {
                // tex coord 2 data offset
                writer.Seek((int)start + 60, System.IO.SeekOrigin.Begin);
                writer.Write((int)(curOffset - start));
                writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

                TexCoordGenIO.Write(writer, m_TexCoord2GenBlock);
            }
            else
            {
                writer.Seek((int)start + 60, System.IO.SeekOrigin.Begin);
                writer.Write((int)0);
                writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);
            }

            curOffset = writer.BaseStream.Position;

            // tex matrix 1 data offset
            writer.Seek((int)start + 64, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            TexMatrixIO.Write(writer, m_TexMatrix1Block);

            curOffset = writer.BaseStream.Position;

            if (m_TexMatrix2Block != null)
            {
                // tex matrix 1 data offset
                writer.Seek((int)start + 68, System.IO.SeekOrigin.Begin);
                writer.Write((int)(curOffset - start));
                writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

                TexMatrixIO.Write(writer, m_TexMatrix2Block);
            }
            else
            {
                writer.Seek((int)start + 60, System.IO.SeekOrigin.Begin);
                writer.Write((int)0);
                writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);
            }

            curOffset = writer.BaseStream.Position;

            // tex number data offset
            writer.Seek((int)start + 72, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            foreach (int inte in m_TexRemapBlock)
            {
                writer.Write((short)inte);
            }

            StreamUtility.PadStreamWithString(writer, 4);

            curOffset = writer.BaseStream.Position;

            // tev order data offset
            writer.Seek((int)start + 76, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            TevOrderIO.Write(writer, m_TevOrderBlock);

            curOffset = writer.BaseStream.Position;

            // tev color data offset
            writer.Seek((int)start + 80, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            Int16ColorIO.Write(writer, m_TevColorBlock);

            curOffset = writer.BaseStream.Position;

            // tev konst color data offset
            writer.Seek((int)start + 84, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            ColorIO.Write(writer, m_TevKonstColorBlock);

            curOffset = writer.BaseStream.Position;

            // tev stage count data offset
            writer.Seek((int)start + 88, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            foreach (byte bt in NumTevStagesBlock)
            {
                writer.Write(bt);
            }

            StreamUtility.PadStreamWithStringByOffset(writer, (int)(writer.BaseStream.Position - curOffset), 4);

            curOffset = writer.BaseStream.Position;

            // tev stage data offset
            writer.Seek((int)start + 92, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            TevStageIO.Write(writer, m_TevStageBlock);

            curOffset = writer.BaseStream.Position;

            // tev swap mode offset
            writer.Seek((int)start + 96, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            TevSwapModeIO.Write(writer, m_SwapModeBlock);

            curOffset = writer.BaseStream.Position;

            // tev swap mode table offset
            writer.Seek((int)start + 100, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            TevSwapModeTableIO.Write(writer, m_SwapTableBlock);

            curOffset = writer.BaseStream.Position;

            // fog data offset
            writer.Seek((int)start + 104, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            FogIO.Write(writer, m_FogBlock);

            curOffset = writer.BaseStream.Position;

            // alpha compare offset
            writer.Seek((int)start + 108, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            AlphaCompareIO.Write(writer, m_AlphaCompBlock);

            curOffset = writer.BaseStream.Position;

            // blend data offset
            writer.Seek((int)start + 112, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            BlendModeIO.Write(writer, m_blendModeBlock);

            curOffset = writer.BaseStream.Position;

            // zmode data offset
            writer.Seek((int)start + 116, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            ZModeIO.Write(writer, m_zModeBlock);

            curOffset = writer.BaseStream.Position;

            // z comp loc data offset
            writer.Seek((int)start + 120, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            foreach (bool bol in m_zCompLocBlock)
            {
                writer.Write(bol);
            }

            StreamUtility.PadStreamWithStringByOffset(writer, (int)(writer.BaseStream.Position - curOffset), 4);

            curOffset = writer.BaseStream.Position;

            if (m_ditherBlock != null)
            {
                // dither data offset
                writer.Seek((int)start + 124, System.IO.SeekOrigin.Begin);
                writer.Write((int)(curOffset - start));
                writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

                foreach (bool bol in m_ditherBlock)
                {
                    writer.Write(bol);
                }

                StreamUtility.PadStreamWithStringByOffset(writer, (int)(writer.BaseStream.Position - curOffset), 4);
            }

            curOffset = writer.BaseStream.Position;

            // NBT Scale data offset
            writer.Seek((int)start + 128, System.IO.SeekOrigin.Begin);
            writer.Write((int)(curOffset - start));
            writer.Seek((int)curOffset, System.IO.SeekOrigin.Begin);

            NBTScaleIO.Write(writer, m_NBTScaleBlock);

            StreamUtility.PadStreamWithString(writer, 32);

            long end    = writer.BaseStream.Position;
            long length = (end - start);

            writer.Seek((int)start + 4, System.IO.SeekOrigin.Begin);
            writer.Write((int)length);
            writer.Seek((int)end, System.IO.SeekOrigin.Begin);
        }
        public MAT3(EndianBinaryReader reader, int offset)
        {
            InitLists();

            reader.BaseStream.Seek(offset, System.IO.SeekOrigin.Begin);

            reader.SkipInt32();
            int  mat3Size      = reader.ReadInt32();
            int  matCount      = reader.ReadInt16();
            long matInitOffset = 0;

            reader.SkipInt16();

            for (Mat3OffsetIndex i = 0; i <= Mat3OffsetIndex.NBTScaleData; ++i)
            {
                int sectionOffset = reader.ReadInt32();

                if (sectionOffset == 0)
                {
                    continue;
                }

                long curReaderPos = reader.BaseStream.Position;
                int  nextOffset   = reader.PeekReadInt32();
                int  sectionSize  = 0;

                if (i == Mat3OffsetIndex.NBTScaleData)
                {
                }

                if (nextOffset == 0 && i != Mat3OffsetIndex.NBTScaleData)
                {
                    long saveReaderPos = reader.BaseStream.Position;

                    reader.BaseStream.Position += 4;

                    while (reader.PeekReadInt32() == 0)
                    {
                        reader.BaseStream.Position += 4;
                    }

                    nextOffset  = reader.PeekReadInt32();
                    sectionSize = nextOffset - sectionOffset;

                    reader.BaseStream.Position = saveReaderPos;
                }
                else if (i == Mat3OffsetIndex.NBTScaleData)
                {
                    sectionSize = mat3Size - sectionOffset;
                }
                else
                {
                    sectionSize = nextOffset - sectionOffset;
                }

                reader.BaseStream.Position = (offset) + sectionOffset;

                switch (i)
                {
                case Mat3OffsetIndex.MaterialData:
                    matInitOffset = reader.BaseStream.Position;
                    break;

                case Mat3OffsetIndex.IndexData:
                    m_RemapIndices = new List <int>();

                    for (int index = 0; index < matCount; index++)
                    {
                        m_RemapIndices.Add(reader.ReadInt16());
                    }

                    break;

                case Mat3OffsetIndex.NameTable:
                    m_MaterialNames = NameTableIO.Load(reader, offset + sectionOffset);
                    break;

                case Mat3OffsetIndex.IndirectData:
                    m_IndirectTexBlock = IndirectTexturingIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.CullMode:
                    m_CullModeBlock = CullModeIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.MaterialColor:
                    m_MaterialColorBlock = ColorIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.ColorChannelCount:
                    NumColorChannelsBlock = new List <byte>();

                    for (int chanCnt = 0; chanCnt < sectionSize; chanCnt++)
                    {
                        byte chanCntIn = reader.ReadByte();

                        if (chanCntIn < 84)
                        {
                            NumColorChannelsBlock.Add(chanCntIn);
                        }
                    }

                    break;

                case Mat3OffsetIndex.ColorChannelData:
                    m_ChannelControlBlock = ColorChannelIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.AmbientColorData:
                    m_AmbientColorBlock = ColorIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.LightData:
                    break;

                case Mat3OffsetIndex.TexGenCount:
                    NumTexGensBlock = new List <byte>();

                    for (int genCnt = 0; genCnt < sectionSize; genCnt++)
                    {
                        byte genCntIn = reader.ReadByte();

                        if (genCntIn < 84)
                        {
                            NumTexGensBlock.Add(genCntIn);
                        }
                    }

                    break;

                case Mat3OffsetIndex.TexCoordData:
                    m_TexCoord1GenBlock = TexCoordGenIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TexCoord2Data:
                    m_TexCoord2GenBlock = TexCoordGenIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TexMatrixData:
                    m_TexMatrix1Block = TexMatrixIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TexMatrix2Data:
                    m_TexMatrix2Block = TexMatrixIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TexNoData:
                    m_TexRemapBlock = new List <short>();
                    int texNoCnt = sectionSize / 2;

                    for (int texNo = 0; texNo < texNoCnt; texNo++)
                    {
                        m_TexRemapBlock.Add(reader.ReadInt16());
                    }

                    break;

                case Mat3OffsetIndex.TevOrderData:
                    m_TevOrderBlock = TevOrderIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TevColorData:
                    m_TevColorBlock = Int16ColorIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TevKColorData:
                    m_TevKonstColorBlock = ColorIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TevStageCount:
                    NumTevStagesBlock = new List <byte>();

                    for (int stgCnt = 0; stgCnt < sectionSize; stgCnt++)
                    {
                        byte stgCntIn = reader.ReadByte();

                        if (stgCntIn < 84)
                        {
                            NumTevStagesBlock.Add(stgCntIn);
                        }
                    }

                    break;

                case Mat3OffsetIndex.TevStageData:
                    m_TevStageBlock = TevStageIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TevSwapModeData:
                    m_SwapModeBlock = TevSwapModeIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.TevSwapModeTable:
                    m_SwapTableBlock = TevSwapModeTableIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.FogData:
                    m_FogBlock = FogIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.AlphaCompareData:
                    m_AlphaCompBlock = AlphaCompareIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.BlendData:
                    m_blendModeBlock = BlendModeIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.ZModeData:
                    m_zModeBlock = ZModeIO.Load(reader, sectionOffset, sectionSize);
                    break;

                case Mat3OffsetIndex.ZCompLoc:
                    m_zCompLocBlock = new List <bool>();

                    for (int zcomp = 0; zcomp < sectionSize; zcomp++)
                    {
                        byte boolIn = reader.ReadByte();

                        if (boolIn > 1)
                        {
                            break;
                        }

                        m_zCompLocBlock.Add(Convert.ToBoolean(boolIn));
                    }

                    break;

                case Mat3OffsetIndex.DitherData:
                    m_ditherBlock = new List <bool>();

                    for (int dith = 0; dith < sectionSize; dith++)
                    {
                        byte boolIn = reader.ReadByte();

                        if (boolIn > 1)
                        {
                            break;
                        }

                        m_ditherBlock.Add(Convert.ToBoolean(boolIn));
                    }

                    break;

                case Mat3OffsetIndex.NBTScaleData:
                    m_NBTScaleBlock = NBTScaleIO.Load(reader, sectionOffset, sectionSize);
                    break;
                }

                reader.BaseStream.Position = curReaderPos;
            }

            int highestMatIndex = 0;

            for (int i = 0; i < matCount; i++)
            {
                if (m_RemapIndices[i] > highestMatIndex)
                {
                    highestMatIndex = m_RemapIndices[i];
                }
            }

            reader.BaseStream.Position = matInitOffset;
            m_Materials = new List <Material>();
            for (int i = 0; i <= highestMatIndex; i++)
            {
                LoadInitData(reader);
            }

            reader.BaseStream.Seek(offset + mat3Size, System.IO.SeekOrigin.Begin);
        }