Esempio n. 1
0
        private static List <Texture2D> LoadTEX1FromFile(EndianBinaryReader reader, long chunkStart)
        {
            ushort           textureCount        = reader.ReadUInt16();
            ushort           padding             = reader.ReadUInt16(); // Usually 0xFFFF?
            uint             textureHeaderOffset = reader.ReadUInt32(); // textureCount # bti image headers are stored here, relative to chunkStart.
            uint             stringTableOffset   = reader.ReadUInt32(); // One filename per texture. relative to chunkStart.
            List <Texture2D> textureList         = new List <Texture2D>();

            // Get all Texture Names
            reader.BaseStream.Position = chunkStart + stringTableOffset;
            StringTable stringTable = StringTable.FromStream(reader);

            for (int t = 0; t < textureCount; t++)
            {
                // 0x20 is the length of the BinaryTextureImage header which all come in a row, but then the stream gets jumped around while loading the BTI file.
                reader.BaseStream.Position = chunkStart + textureHeaderOffset + (t * 0x20);
                BinaryTextureImage texture = new BinaryTextureImage();
                texture.Load(reader, chunkStart + 0x20, t);

                Texture2D texture2D = new Texture2D(texture.Width, texture.Height);
                texture2D.Name      = stringTable[t];
                texture2D.PixelData = texture.GetData();
                textureList.Add(texture2D);


                string executionPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                texture.SaveImageToDisk(executionPath + "/TextureDump/" + string.Format("{0}_({1}-{2}).png", stringTable[t], texture.Format, t));
            }

            return(textureList);
        }
Esempio n. 2
0
        private void LoadTagDataFromFile(EndianBinaryReader reader, int tagCount)
        {
            for (int i = 0; i < tagCount; i++)
            {
                long tagStart = reader.BaseStream.Position;

                string tagName = reader.ReadString(4);
                int    tagSize = reader.ReadInt32();

                switch (tagName)
                {
                case "TTK1":
                    LoopMode = (LoopType)reader.ReadByte();                           // 0 = Play Once. 2 = Loop (Assumed from BCK)
                    byte angleMultiplier = reader.ReadByte();                         // Multiply Angle Value by pow(2, angleMultiplier) (Assumed from BCK)
                    AnimLengthInFrames = reader.ReadInt16();
                    short textureAnimEntryCount    = (short)(reader.ReadInt16() / 3); // 3 for each material. BTK stores U, V, and W separately, so you need to divide by three.
                    short numScaleFloatEntries     = reader.ReadInt16();
                    short numRotationShortEntries  = reader.ReadInt16();
                    short numTranslateFloatEntries = reader.ReadInt16();
                    int   animDataOffset           = reader.ReadInt32();
                    int   remapTableOffset         = reader.ReadInt32();
                    int   stringTableOffset        = reader.ReadInt32();
                    int   textureIndexTableOffset  = reader.ReadInt32();
                    int   textureCenterTableOffset = reader.ReadInt32();
                    int   scaleDataOffset          = reader.ReadInt32();
                    int   rotationDataOffset       = reader.ReadInt32();
                    int   translateDataOffset      = reader.ReadInt32();

                    // Read array of scale data
                    float[] scaleData = new float[numScaleFloatEntries];
                    reader.BaseStream.Position = tagStart + scaleDataOffset;
                    for (int j = 0; j < numScaleFloatEntries; j++)
                    {
                        scaleData[j] = reader.ReadSingle();
                    }

                    // Read array of rotation data (but don't convert it)
                    float[] rotationData = new float[numRotationShortEntries];
                    reader.BaseStream.Position = tagStart + rotationDataOffset;
                    for (int j = 0; j < numRotationShortEntries; j++)
                    {
                        rotationData[j] = reader.ReadInt16();
                    }

                    // Read array of translation/position data
                    float[] translationData = new float[numTranslateFloatEntries];
                    reader.BaseStream.Position = tagStart + translateDataOffset;
                    for (int j = 0; j < numTranslateFloatEntries; j++)
                    {
                        translationData[j] = reader.ReadSingle();
                    }

                    // Remap Table (probably matches MAT3's remap table?)
                    m_remapTable = new short[textureAnimEntryCount];
                    reader.BaseStream.Position = tagStart + remapTableOffset;
                    for (int j = 0; j < textureAnimEntryCount; j++)
                    {
                        m_remapTable[j] = reader.ReadInt16();
                    }

                    // String Table which gives us material names.
                    reader.BaseStream.Position = tagStart + stringTableOffset;
                    StringTable stringTable = StringTable.FromStream(reader);

                    // Texture Index table which tells us which texture index of this material to modify (?)
                    byte[] texMtxIndexTable = new byte[textureAnimEntryCount];
                    reader.BaseStream.Position = tagStart + textureIndexTableOffset;
                    for (int j = 0; j < textureAnimEntryCount; j++)
                    {
                        texMtxIndexTable[j] = reader.ReadByte();
                    }

                    // Texture Centers
                    Vector3[] textureCenters = new Vector3[textureAnimEntryCount];
                    reader.BaseStream.Position = tagStart + textureCenterTableOffset;
                    for (int j = 0; j < textureAnimEntryCount; j++)
                    {
                        textureCenters[j] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                    }

                    // Read the data for each joint that this animation.
                    m_animationData = new List <MaterialAnim>();
                    float rotScale = (float)Math.Pow(2f, angleMultiplier) * (180 / 32768f);

                    reader.BaseStream.Position = tagStart + animDataOffset;
                    for (int j = 0; j < textureAnimEntryCount; j++)
                    {
                        AnimComponent texU = ReadAnimComponent(reader);
                        AnimComponent texV = ReadAnimComponent(reader);
                        AnimComponent texW = ReadAnimComponent(reader);

                        MaterialAnim anim = new MaterialAnim();
                        anim.Name           = stringTable[j];
                        anim.TexMatrixIndex = texMtxIndexTable[j];
                        anim.Center         = textureCenters[j];

                        anim.ScalesX = ReadComp(scaleData, texU.Scale);
                        anim.ScalesY = ReadComp(scaleData, texV.Scale);
                        anim.ScalesZ = ReadComp(scaleData, texW.Scale);

                        anim.RotationsX = ReadComp(rotationData, texU.Rotation);
                        anim.RotationsY = ReadComp(rotationData, texV.Rotation);
                        anim.RotationsZ = ReadComp(rotationData, texW.Rotation);

                        // Convert all of the rotations from compressed shorts back into -180, 180
                        ConvertRotation(anim.RotationsX, rotScale);
                        ConvertRotation(anim.RotationsY, rotScale);
                        ConvertRotation(anim.RotationsZ, rotScale);

                        anim.TranslationsX = ReadComp(translationData, texU.Translation);
                        anim.TranslationsY = ReadComp(translationData, texV.Translation);
                        anim.TranslationsZ = ReadComp(translationData, texW.Translation);

                        m_animationData.Add(anim);
                    }
                    break;
                }

                // Skip the stream reader to the start of the next tag since it gets moved around during loading.
                reader.BaseStream.Position = tagStart + tagSize;
            }
        }
Esempio n. 3
0
        private void LoadTagDataFromFile(EndianBinaryReader reader)
        {
            long tagStart = reader.BaseStream.Position;

            string tagName = reader.ReadString(4);
            int    tagSize = reader.ReadInt32();

            LoopMode = (LoopType)reader.ReadByte();
            byte angleMultiplier = reader.ReadByte(); // Probably just padding in BRK

            AnimLengthInFrames = reader.ReadInt16();
            short colorAnimEntryCount = reader.ReadInt16();
            short konstAnimEntryCount = reader.ReadInt16();

            short numColorREntries = reader.ReadInt16();
            short numColorGEntries = reader.ReadInt16();
            short numColorBEntries = reader.ReadInt16();
            short numColorAEntries = reader.ReadInt16();

            short numKonstREntries = reader.ReadInt16();
            short numKonstGEntries = reader.ReadInt16();
            short numKonstBEntries = reader.ReadInt16();
            short numKonstAEntries = reader.ReadInt16();

            int colorAnimDataOffset = reader.ReadInt32();
            int konstAnimDataOffset = reader.ReadInt32();

            int colorRemapTableOffset = reader.ReadInt32();
            int konstRemapTableOffset = reader.ReadInt32();

            int colorStringTableOffset = reader.ReadInt32();
            int konstStringTableOffset = reader.ReadInt32();

            int colorRTableOffset = reader.ReadInt32();
            int colorGTableOffset = reader.ReadInt32();
            int colorBTableOffset = reader.ReadInt32();
            int colorATableOffset = reader.ReadInt32();

            int konstRTableOffset = reader.ReadInt32();
            int konstGTableOffset = reader.ReadInt32();
            int konstBTableOffset = reader.ReadInt32();
            int konstATableOffset = reader.ReadInt32();

            reader.Skip(8); // padding

            float[] colorRData = new float[numColorREntries];
            reader.BaseStream.Position = tagStart + colorRTableOffset;
            for (int i = 0; i < numColorREntries; i++)
            {
                colorRData[i] = reader.ReadInt16();
            }

            float[] colorGData = new float[numColorGEntries];
            reader.BaseStream.Position = tagStart + colorGTableOffset;
            for (int i = 0; i < numColorGEntries; i++)
            {
                colorGData[i] = reader.ReadInt16();
            }

            float[] colorBData = new float[numColorBEntries];
            reader.BaseStream.Position = tagStart + colorBTableOffset;
            for (int i = 0; i < numColorBEntries; i++)
            {
                colorBData[i] = reader.ReadInt16();
            }

            float[] colorAData = new float[numColorAEntries];
            reader.BaseStream.Position = tagStart + colorATableOffset;
            for (int i = 0; i < numColorAEntries; i++)
            {
                colorAData[i] = reader.ReadInt16();
            }

            float[] konstRData = new float[numKonstREntries];
            reader.BaseStream.Position = tagStart + konstRTableOffset;
            for (int i = 0; i < numKonstREntries; i++)
            {
                konstRData[i] = reader.ReadInt16();
            }

            float[] konstGData = new float[numKonstGEntries];
            reader.BaseStream.Position = tagStart + konstGTableOffset;
            for (int i = 0; i < numKonstGEntries; i++)
            {
                konstGData[i] = reader.ReadInt16();
            }

            float[] konstBData = new float[numKonstBEntries];
            reader.BaseStream.Position = tagStart + konstBTableOffset;
            for (int i = 0; i < numKonstBEntries; i++)
            {
                konstBData[i] = reader.ReadInt16();
            }

            float[] konstAData = new float[numKonstAEntries];
            reader.BaseStream.Position = tagStart + konstATableOffset;
            for (int i = 0; i < numKonstAEntries; i++)
            {
                konstAData[i] = reader.ReadInt16();
            }

            m_colorRemapTable          = new int[colorAnimEntryCount];
            reader.BaseStream.Position = tagStart + colorRemapTableOffset;
            for (int i = 0; i < colorAnimEntryCount; i++)
            {
                m_colorRemapTable[i] = reader.ReadInt16();
            }

            m_konstRemapTable          = new int[konstAnimEntryCount];
            reader.BaseStream.Position = tagStart + konstRemapTableOffset;
            for (int i = 0; i < konstAnimEntryCount; i++)
            {
                m_konstRemapTable[i] = reader.ReadInt16();
            }

            reader.BaseStream.Position = tagStart + colorStringTableOffset;
            m_colorStringTable         = StringTable.FromStream(reader);

            reader.BaseStream.Position = tagStart + konstStringTableOffset;
            m_konstStringTable         = StringTable.FromStream(reader);

            m_colorAnimationData = new List <RegisterAnim>();

            reader.BaseStream.Position = tagStart + colorAnimDataOffset;
            for (int i = 0; i < colorAnimEntryCount; i++)
            {
                AnimIndex colorRIndex = ReadAnimIndex(reader);
                AnimIndex colorGIndex = ReadAnimIndex(reader);
                AnimIndex colorBIndex = ReadAnimIndex(reader);
                AnimIndex colorAIndex = ReadAnimIndex(reader);
                int       colorID     = reader.ReadByte();
                reader.Skip(3);

                RegisterAnim regAnim = new RegisterAnim();
                regAnim.ColorID = colorID;

                regAnim.RedChannel   = ReadComp(colorRData, colorRIndex);
                regAnim.GreenChannel = ReadComp(colorGData, colorGIndex);
                regAnim.BlueChannel  = ReadComp(colorBData, colorBIndex);
                regAnim.AlphaChannel = ReadComp(colorAData, colorAIndex);

                foreach (Key key in regAnim.RedChannel)
                {
                    key.Value      = key.Value / 255.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                foreach (Key key in regAnim.GreenChannel)
                {
                    key.Value      = key.Value / 255.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                foreach (Key key in regAnim.BlueChannel)
                {
                    key.Value      = key.Value / 255.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                foreach (Key key in regAnim.AlphaChannel)
                {
                    key.Value      = key.Value / 255.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                m_colorAnimationData.Add(regAnim);
            }

            m_konstAnimationData = new List <RegisterAnim>();

            reader.BaseStream.Position = tagStart + konstAnimDataOffset;
            for (int i = 0; i < konstAnimEntryCount; i++)
            {
                AnimIndex konstRIndex = ReadAnimIndex(reader);
                AnimIndex konstGIndex = ReadAnimIndex(reader);
                AnimIndex konstBIndex = ReadAnimIndex(reader);
                AnimIndex konstAIndex = ReadAnimIndex(reader);
                int       colorID     = reader.ReadByte();
                reader.Skip(3);

                RegisterAnim regAnim = new RegisterAnim();
                regAnim.ColorID = colorID;

                regAnim.RedChannel   = ReadComp(konstRData, konstRIndex);
                regAnim.GreenChannel = ReadComp(konstGData, konstGIndex);
                regAnim.BlueChannel  = ReadComp(konstBData, konstBIndex);
                regAnim.AlphaChannel = ReadComp(konstAData, konstAIndex);

                foreach (Key key in regAnim.RedChannel)
                {
                    key.Value      = key.Value / 65535.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                foreach (Key key in regAnim.GreenChannel)
                {
                    key.Value      = key.Value / 255.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                foreach (Key key in regAnim.BlueChannel)
                {
                    key.Value      = key.Value / 255.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                foreach (Key key in regAnim.AlphaChannel)
                {
                    key.Value      = key.Value / 255.0f;
                    key.TangentIn  = (float)key.TangentIn / 65535.0f;
                    key.TangentOut = (float)key.TangentOut / 65535.0f;
                }

                m_konstAnimationData.Add(regAnim);
            }
        }
Esempio n. 4
0
        private static List <SkeletonBone> LoadJNT1SectionFromStream(EndianBinaryReader reader, long chunkStart)
        {
            List <SkeletonBone> skeletonBones = new List <SkeletonBone>();

            ushort numJoints         = reader.ReadUInt16();
            ushort padding           = reader.ReadUInt16();
            uint   jointDataOffset   = reader.ReadUInt32(); // Relative to JNT1 Header Start
            uint   jointRemapOffset  = reader.ReadUInt32();
            uint   stringTableOffset = reader.ReadUInt32();

            // Grab the joint names from file
            reader.BaseStream.Position = chunkStart + stringTableOffset;
            StringTable jointNames = StringTable.FromStream(reader);

            // This is always 0 to (numJoints-1) - unsure if it's a joint
            // remap (likely) or a string-table remap (less likely). It's unknown
            // if any models don't follow this 0 to (n-1) pattern.
            ushort[] jointRemaps = new ushort[numJoints];
            reader.BaseStream.Position = chunkStart + jointRemapOffset;
            for (int j = 0; j < numJoints; j++)
            {
                jointRemaps[j] = reader.ReadUInt16();
            }

            // Grab the actual joints
            reader.BaseStream.Position = chunkStart + jointDataOffset;
            for (int j = 0; j < numJoints; j++)
            {
                SkeletonBone bone = new SkeletonBone();

                bone.Name = jointNames[j];
                ushort unknown1 = reader.ReadUInt16();  // Values of 0, 2 or 1. yaz0r calls it Matrix Type (referring to 'MatrixTable' which is an index into DRW1 - Draw type?
                                                        // If value is 1 or 2 then Bounding Box / Radius is Vector3.Zero / 0f
                                                        // And seems to be 0 if a joint has direct non-joint children (Maybe 0 is a 'bone with children' and the BBMin/Max contain
                                                        // the bounds of children?
                ushort unknown2 = reader.ReadUInt16();  // No one seems to know what it is, often 0xFF or 0 or 1. May be two individual bytes with a pad afterwards.

                for (int f = 0; f < 3; f++)
                {
                    bone.Scale[f] = reader.ReadSingle();
                }

                Vector3 eulerAngles = new Vector3();
                for (int f = 0; f < 3; f++)
                {
                    eulerAngles[f] = (reader.ReadInt16() * (180 / 32786f));
                }

                Quaternion xAxis = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), eulerAngles.X * MathE.Deg2Rad);
                Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), eulerAngles.Y * MathE.Deg2Rad);
                Quaternion zAxis = Quaternion.FromAxisAngle(new Vector3(0, 0, 1), eulerAngles.Z * MathE.Deg2Rad);

                // Swizzling to the ZYX order seems to be the right one.
                Quaternion finalRot = zAxis * yAxis * xAxis;

                bone.Rotation = finalRot;
                Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding
                for (int f = 0; f < 3; f++)
                {
                    bone.Translation[f] = reader.ReadSingle();
                }
                bone.BoundingSphereDiameter = reader.ReadSingle();
                for (int f = 0; f < 3; f++)
                {
                    bone.BoundingBoxMin[f] = reader.ReadSingle();
                }
                for (int f = 0; f < 3; f++)
                {
                    bone.BoundingBoxMax[f] = reader.ReadSingle();
                }

                skeletonBones.Add(bone);
            }
            return(skeletonBones);
        }
Esempio n. 5
0
        public List <Material> LoadMAT3SectionFromStream(EndianBinaryReader reader, long chunkStart, int chunkSize)
        {
            short materialCount = reader.ReadInt16();

            Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding


            // Nintendo sets unused offsets to zero, so we can't just use the next variable name in the list. Instead we have to search
            // until we find a non-zero one and calculate the difference that way. Thus, we convert all of the offsets into an int[] for
            // array operations.
            int[] offsets = new int[30];
            for (int i = 0; i < offsets.Length; i++)
            {
                offsets[i] = reader.ReadInt32();
            }

            List <Material> materialList = new List <Material>();

            /* MATERIAL REMAP TABLE (See start of Material loader below) */
            var matIndexToMaterial = ReadSection <short>(reader, chunkStart, chunkSize, offsets, 1, ReadShort, 2);

            /* STRING TABLE */
            reader.BaseStream.Position = chunkStart + offsets[2];
            StringTable nameTable = StringTable.FromStream(reader);

            /* INDIRECT TEXTURING */
            // ???????

            /* CULL MODE */
            var cullModes = ReadSection <int>(reader, chunkStart, chunkSize, offsets, 4, ReadInt32, 4);

            /* MATERIAL COLOR */
            var materialColors = ReadSection <Color>(reader, chunkStart, chunkSize, offsets, 5, ReadColor32, 4);

            /* NUM COLOR CHAN */
            // THIS IS A GUESS AT DATA TYPE
            var numChannelControls = ReadSection <byte>(reader, chunkStart, chunkSize, offsets, 6, ReadByte, 1);

            /* COLOR CHAN INFO */
            var colorChannelInfos = ReadSection <ChanCtrl>(reader, chunkStart, chunkSize, offsets, 7, ReadChannelControl, 8);

            /* AMBIENT COLOR */
            var ambientColors = ReadSection <Color>(reader, chunkStart, chunkSize, offsets, 8, ReadColor32, 4);

            /* LIGHT INFO */
            // THIS IS A GUESS AT DATA TYPE
            var lightingColors = ReadSection <Color>(reader, chunkStart, chunkSize, offsets, 9, ReadColorShort, 8);

            /* TEX GEN NUMBER */
            var numTexGens = ReadSection <byte>(reader, chunkStart, chunkSize, offsets, 10, ReadByte, 1);

            /* TEX GEN INFO */
            var texGenInfos = ReadSection <TexCoordGen>(reader, chunkStart, chunkSize, offsets, 11, ReadTexCoordGen, 4);

            /* TEX GEN 2 INFO */
            var texGen2Infos = ReadSection <TexCoordGen>(reader, chunkStart, chunkSize, offsets, 12, ReadTexCoordGen, 4);

            /* TEX MATRIX INFO */
            var texMatrixInfo = ReadSection <TexMatrix>(reader, chunkStart, chunkSize, offsets, 13, ReadTexMatrix, 100);

            /* POST TRANSFORM MATRIX INFO */
            var texMatrix2Info = ReadSection <TexMatrix>(reader, chunkStart, chunkSize, offsets, 14, ReadTexMatrix, 100);

            /* TEXURE INDEX */
            var texIndexes = ReadSection <short>(reader, chunkStart, chunkSize, offsets, 15, ReadShort, 2);

            /* TEV ORDER INFO */
            var tevOrderInfos = ReadSection <TevOrder>(reader, chunkStart, chunkSize, offsets, 16, ReadTevOrder, 4);

            /* TEV COLORS */
            var tevColors = ReadSection <Color>(reader, chunkStart, chunkSize, offsets, 17, ReadColorShort, 8);

            /* TEV KONST COLORS */
            var tevKonstColors = ReadSection <Color>(reader, chunkStart, chunkSize, offsets, 18, ReadColor32, 4);

            /* NUM TEV STAGES */
            // THIS IS A GUESS AT DATA TYPE
            var numTevStages = ReadSection <byte>(reader, chunkStart, chunkSize, offsets, 19, ReadByte, 1);

            /* TEV STAGE INFO */
            var tevStageInfos = ReadSection <TevStage>(reader, chunkStart, chunkSize, offsets, 20, ReadTevCombinerStage, 20);

            /* TEV SWAP MODE INFO */
            var tevSwapModeInfos = ReadSection <TevSwapMode>(reader, chunkStart, chunkSize, offsets, 21, ReadTevSwapMode, 4);

            /* TEV SWAP MODE TABLE INFO */
            var tevSwapModeTables = ReadSection <TevSwapModeTable>(reader, chunkStart, chunkSize, offsets, 22, ReadTevSwapModeTable, 4);

            /* FOG INFO */
            var fogInfos = ReadSection <FogInfo>(reader, chunkStart, chunkSize, offsets, 23, ReadFogInfo, 44);

            /* ALPHA COMPARE INFO */
            var alphaCompares = ReadSection <AlphaCompare>(reader, chunkStart, chunkSize, offsets, 24, ReadAlphaCompare, 8);

            /* BLEND INFO */
            var blendModeInfos = ReadSection <BlendMode>(reader, chunkStart, chunkSize, offsets, 25, ReadBlendMode, 4);

            /* ZMODE INFO */
            var zModeInfos = ReadSection <ZMode>(reader, chunkStart, chunkSize, offsets, 26, ReadZMode, 4);

            /* ZCOMP LOC INFO */
            // THIS IS A GUESS AT DATA TYPE
            var zCompLocInfos = ReadSection <bool>(reader, chunkStart, chunkSize, offsets, 27, ReadBool, 1);

            /* DITHER INFO */
            // THIS IS A GUESS AT DATA TYPE
            var ditherInfos = ReadSection <bool>(reader, chunkStart, chunkSize, offsets, 28, ReadBool, 1);

            /* NBT SCALE INFO */
            // ????


            for (int m = 0; m < materialCount; m++)
            {
                // A MAT3 section can potentially specify more materials than there is actually material data for. For example,
                // Link (cl.bdl) specifies 24 materials, but anything after m = 16 doesn't exist. This is because if you examine
                // the materialRemap table, we can see that indexes 17+ all point back to 0. It appears they duplicated his materials
                // and when the tool exported them, it crushed the actual Material structures down to non-duplicates but left the
                // stuff referencing the old one. We're going to read each one as a unique material (by overwriting the index we
                // read from) after going through the material lookup table. This removes the duplicates when we load them and turns
                // them all into unique instances.
                int matIndex = matIndexToMaterial[m];


                // A Material entry is 0x14c long.
                reader.BaseStream.Position = chunkStart + offsets[0] + (matIndex * 0x14c);

                // The first byte of a material is some form of flag. Values found so far are 1, 4 and 0. 1 is the most common.
                // bmdview2 documentation says that means "draw on way down" while 4 means "draw on way up" (of INF1 heirarchy)
                // However, none of the documentation seems to mention type 0 - if the value is 0, it seems to be some junk/EOF
                // marker for the material section. On some files (not all) there will be say, 12 materials, but the highest index
                // in the material remap table only goes up to 10 (so the 11th material) and the 12th will never be referenced. However
                // if we read it like we do here with a for loop, we'll hit that one and try to parse all the indexes and it'll just all
                // around kind of explode.
                //
                // To resolve this, we'll check if the flag value is zero - if so, skip creating a material for it.

                byte flag = reader.ReadByte();
                if (flag == 0)
                {
                    continue;
                }

                // Now that we've read the contents of the material section, we can load their values into a material
                // class which keeps it nice and tidy and full of class references and not indexes.
                WEditor.Common.Nintendo.J3D.Material material = new WEditor.Common.Nintendo.J3D.Material();
                materialList.Add(material);

                material.Name               = nameTable[m];
                material.Flag               = flag;
                material.CullMode           = (GXCullMode)cullModes[reader.ReadByte()];
                material.NumChannelControls = numChannelControls[reader.ReadByte()];
                material.NumTexGens         = numTexGens[reader.ReadByte()];
                material.NumTevStages       = numTevStages[reader.ReadByte()];
                material.ZCompLoc           = zCompLocInfos[reader.ReadByte()];
                material.ZMode              = zModeInfos[reader.ReadByte()];
                material.Dither             = ditherInfos[reader.ReadByte()];

                // Not sure what these materials are used for. gxColorMaterial is the function that reads them.
                material.MaterialColors = new Color[2];
                for (int i = 0; i < material.MaterialColors.Length; i++)
                {
                    short index = reader.ReadInt16();
                    material.MaterialColors[i] = materialColors[index];
                }

                material.ChannelControls = new ChanCtrl[4];
                for (int i = 0; i < material.ChannelControls.Length; i++)
                {
                    material.ChannelControls[i] = colorChannelInfos[reader.ReadInt16()];
                }

                material.AmbientColors = new Color[2];
                for (int i = 0; i < material.AmbientColors.Length; i++)
                {
                    material.AmbientColors[i] = ambientColors[reader.ReadInt16()];
                }

                material.LightingColors = new Color[8];
                for (int i = 0; i < material.LightingColors.Length; i++)
                {
                    // Index will be -1 if there's no Lighting Colors on this material.
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.LightingColors[i] = lightingColors[index];
                    }
                }

                material.TexGenInfos = new TexCoordGen[8];
                for (int i = 0; i < material.TexGenInfos.Length; i++)
                {
                    // Index will be -1 if there's no Tex Gens on this material.
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.TexGenInfos[i] = texGenInfos[index];
                    }
                }

                material.TexGen2Infos = new TexCoordGen[8];
                for (int i = 0; i < material.TexGen2Infos.Length; i++)
                {
                    // Index will be -1 if there's no Tex Gen 2s on this material.
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.TexGen2Infos[i] = texGenInfos[index];
                    }
                }

                material.TexMatrices = new TexMatrix[10];
                for (int i = 0; i < material.TexMatrices.Length; i++)
                {
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.TexMatrices[i] = texMatrixInfo[index];
                    }
                }

                material.DttMatrices = new TexMatrix[20];
                for (int i = 0; i < material.DttMatrices.Length; i++)
                {
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.DttMatrices[i] = texMatrix2Info[index];
                    }
                }

                material.TextureIndexes = new short[8] {
                    -1, -1, -1, -1, -1, -1, -1, -1
                };
                for (int i = 0; i < material.TextureIndexes.Length; i++)
                {
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.TextureIndexes[i] = texIndexes[index];
                    }
                }

                material.TevKonstColors = new Color[4];
                for (int i = 0; i < material.TevKonstColors.Length; i++)
                {
                    material.TevKonstColors[i] = tevKonstColors[reader.ReadInt16()];
                }

                // Guessing that this one doesn't index anything else as it's just an enum value and there doesn't seem to be an offset for it in the header.
                material.KonstColorSels = new GXKonstColorSel[16];
                for (int i = 0; i < material.KonstColorSels.Length; i++)
                {
                    material.KonstColorSels[i] = (GXKonstColorSel)reader.ReadByte();
                }

                // Guessing that this one doesn't index anything else as it's just an enum value and there doesn't seem to be an offset for it in the header.
                material.KonstAlphaSels = new GXKonstAlphaSel[16];
                for (int i = 0; i < material.KonstAlphaSels.Length; i++)
                {
                    material.KonstAlphaSels[i] = (GXKonstAlphaSel)reader.ReadByte();
                }

                material.TevOrderInfos = new TevOrder[16];
                for (int i = 0; i < material.TevOrderInfos.Length; i++)
                {
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.TevOrderInfos[i] = tevOrderInfos[index];
                    }
                }

                material.TevColor = new Color[4];
                for (int i = 0; i < material.TevColor.Length; i++)
                {
                    material.TevColor[i] = tevColors[reader.ReadInt16()];
                }

                material.TevStageInfos = new TevStage[16];
                for (int i = 0; i < material.TevStageInfos.Length; i++)
                {
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.TevStageInfos[i] = tevStageInfos[index];
                    }
                }

                material.TevSwapModes = new TevSwapMode[16];
                for (int i = 0; i < material.TevSwapModes.Length; i++)
                {
                    short index = reader.ReadInt16();
                    if (index >= 0)
                    {
                        material.TevSwapModes[i] = tevSwapModeInfos[index];
                    }
                }

                material.TevSwapModeTables = new TevSwapModeTable[4];
                for (int i = 0; i < material.TevSwapModeTables.Length; i++)
                {
                    material.TevSwapModeTables[i] = tevSwapModeTables[reader.ReadInt16()];
                }

                material.UnknownIndexes = new short[12];
                for (int l = 0; l < material.UnknownIndexes.Length; l++)
                {
                    material.UnknownIndexes[l] = reader.ReadInt16();
                }

                short fogIndex = reader.ReadInt16();
                material.Fog = fogInfos[fogIndex];

                short alphaCompareIndex = reader.ReadInt16();
                material.AlphaCompare  = alphaCompares[alphaCompareIndex];
                material.BlendMode     = blendModeInfos[reader.ReadInt16()];
                material.UnknownIndex2 = reader.ReadInt16();
            }

            return(materialList);
        }