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); }
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; } }
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); } }
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); }
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); }