public static TextureMapEntry ReadTextureMapEntry(MemoryStream texMap, MEGame game, List <string> packageNames) { TextureMapEntry tme = new TextureMapEntry(); tme.Name = texMap.ReadStringASCII(texMap.ReadByte()); tme.CRC = texMap.ReadUInt32(); tme.Width = texMap.ReadInt16(); tme.Height = texMap.ReadInt16(); tme.PixelFormat = (PixelFormat)texMap.ReadByte(); tme.Flags = texMap.ReadByte(); int countPackages = texMap.ReadInt16(); for (int k = 0; k < countPackages; k++) { TextureMapPackageEntry matched = new TextureMapPackageEntry(); matched.UIndex = texMap.ReadInt32(); if (game == ME3ExplorerCore.Packages.MEGame.ME1) { var isSlaveTexture = texMap.ReadInt16(); if (isSlaveTexture != -1) { matched.IsSlave = true; //This file has external mips that point to a master package file matched.MasterPackageName = texMap.ReadStringASCIINull(); } matched.TextureOffset = texMap.ReadUInt32(); } matched.NumEmptyMips = texMap.ReadByte(); matched.NumMips = texMap.ReadByte(); //matched.IsMovieTexture = (texture.flags == TextureProperty::TextureTypes::Movie); var packageIndex = texMap.ReadInt16(); matched.RelativePackagePath = packageNames[packageIndex].Replace("\\", "/"); // Not sure what pkgs is matched.PackageName = Path.GetFileName(matched.RelativePackagePath); tme.ContainingPackages.Add(matched); } return(tme); }
void ReadMaterial() { if (clyt.Materials.Count > 0) { throw new FormatException("Expecting just one mat1 section"); } long baseOffset = reader.Stream.Position - 8; int numMaterials = reader.ReadInt32(); while (numMaterials > 0) { // Read from table and jump to material long offset = baseOffset + reader.ReadUInt32(); reader.Stream.PushToPosition(offset); var material = new Material(); material.Name = reader.ReadString(0x14).Replace("\0", string.Empty); for (int i = 0; i < material.TevConstantColors.Length; i++) { // TODO: Convert to RGBA material.TevConstantColors[i] = reader.ReadUInt32(); } uint flags = reader.ReadUInt32(); uint numTexMap = flags & 0x3; uint numTexMatrix = (flags >> 2) & 0x3; uint numTexCoordGen = (flags >> 4) & 0x3; uint numTevStage = (flags >> 6) & 0x7; bool hasAlphaCompare = ((flags >> 9) & 0x01) == 1; bool hasBlendMode = ((flags >> 10) & 0x01) == 1; material.UseTextureOnly = ((flags >> 11) & 0x01) == 1; bool separateBlendMode = ((flags >> 12) & 0x01) == 1; bool hasIndirectParam = ((flags >> 13) & 0x01) == 1; uint numProjTexGenParam = (flags >> 14) & 0x03; bool hasFontShadowParam = ((flags >> 16) & 0x01) == 1; for (int i = 0; i < numTexMap; i++) { var entry = new TextureMapEntry(); entry.Index = reader.ReadUInt16(); byte flag1 = reader.ReadByte(); byte flag2 = reader.ReadByte(); entry.WrapS = (WrapMode)(flag1 & 0x3); entry.WrapT = (WrapMode)(flag2 & 0x3); entry.MinFilter = (TextureFilter)((flag1 >> 2) & 0x3); entry.MagFilter = (TextureFilter)((flag2 >> 2) & 0x3); material.TexMapEntries.Add(entry); } for (int i = 0; i < numTexMatrix; i++) { var entry = new TextureMatrixEntry(); entry.Translation = new Vector2(reader.ReadSingle(), reader.ReadSingle()); entry.Rotation = reader.ReadSingle(); entry.Scale = new Vector2(reader.ReadSingle(), reader.ReadSingle()); material.TexMatrixEntries.Add(entry); } for (int i = 0; i < numTexCoordGen; i++) { material.TextureCoordGen.Add(reader.ReadSingle()); } for (int i = 0; i < numTevStage; i++) { var stage = new TevStage(); stage.Param1 = reader.ReadUInt32(); stage.Param2 = reader.ReadUInt32(); stage.Param3 = reader.ReadUInt32(); material.TevStages.Add(stage); } if (hasAlphaCompare) { material.AlphaCompare = new AlphaCompare { Function = reader.ReadUInt32(), Reference = reader.ReadSingle(), }; } if (hasBlendMode) { material.ColorBlendMode = new BlendMode { BlendOperator = reader.ReadByte(), SourceFactor = reader.ReadByte(), DestinationFactor = reader.ReadByte(), LogicOperator = reader.ReadByte(), }; } if (separateBlendMode) { material.AlphaBlendMode = new BlendMode { BlendOperator = reader.ReadByte(), SourceFactor = reader.ReadByte(), DestinationFactor = reader.ReadByte(), LogicOperator = reader.ReadByte(), }; } if (hasIndirectParam || numProjTexGenParam > 0 || hasFontShadowParam) { Console.WriteLine($"WARN: Material ({material.Name}) with unknown sections."); } clyt.Materials.Add(material); reader.Stream.PopPosition(); numMaterials--; } }
public static Dictionary <uint, TextureMapEntry> LoadTextureMap(MEGame game) { // Read the vanilla file name table List <string> packageNames = null; { using var stream = File.OpenRead(Path.Combine(App.ExecFolder, @"TextureMap", $@"vanilla{game}.bin")); if (stream.ReadStringASCII(4) != @"MD5T") { throw new Exception(@"Header of MD5 table doesn't match expected value!"); } //Decompress var decompressedSize = stream.ReadInt32(); //var compressedSize = stream.Length - stream.Position; var compressedBuffer = stream.ReadToBuffer(stream.Length - stream.Position); var decompressedBuffer = LZMA.Decompress(compressedBuffer, (uint)decompressedSize); if (decompressedBuffer.Length != decompressedSize) { throw new Exception(@"Vanilla database failed to decompress"); } //Read MemoryStream table = new MemoryStream(decompressedBuffer); int numEntries = table.ReadInt32(); packageNames = new List <string>(numEntries); //Package names for (int i = 0; i < numEntries; i++) { //Read entry packageNames.Add(table.ReadStringASCIINull().Replace('/', '\\').TrimStart('\\')); } } var tmf = Path.Combine(App.ExecFolder, @"TextureMap", $@"vanilla{game}Map.bin"); using var fs = File.OpenRead(tmf); // read the precomputed vanilla texture map. // this map will help identify vanilla textures var magic = fs.ReadInt32(); if (magic != 0x504D5443) { throw new Exception(@"Invalid precomputed texture map! Wrong magic"); } var decompSize = fs.ReadUInt32(); byte[] compresssed = fs.ReadToBuffer(fs.ReadInt32()); var texMap = new MemoryStream(LZMA.Decompress(compresssed, decompSize)); texMap.Seek(8, SeekOrigin.Begin); // skip magic, ??? var textureCount = texMap.ReadInt32(); Dictionary <uint, TextureMapEntry> map = new Dictionary <uint, TextureMapEntry>(textureCount); for (int i = 0; i < textureCount; i++) { var entry = TextureMapEntry.ReadTextureMapEntry(texMap, game, packageNames); map[entry.CRC] = entry; } return(map); }
void ReadMaterial() { if (clyt.Materials.Count > 0) { throw new FormatException("Expecting just one mat1 section"); } long baseOffset = reader.Stream.Position - 8; int numMaterials = reader.ReadInt32(); while (numMaterials > 0) { // Read from table and jump to material long offset = baseOffset + reader.ReadUInt32(); reader.Stream.PushToPosition(offset); var material = new Material(); material.Name = reader.ReadString(0x14).Replace("\0", string.Empty); for (int i = 0; i < material.TevConstantColors.Length; i++) { // TODO: Convert to RGBA material.TevConstantColors[i] = reader.ReadUInt32(); } uint flags = reader.ReadUInt32(); uint numTexMap = flags & 0x3; uint numTexMatrix = (flags >> 2) & 0x3; uint numTexCoordGen = (flags >> 4) & 0x3; uint numTevStage = (flags >> 6) & 0x7; uint hasAlphaCompare = (flags >> 9) & 0x01; uint hasBlendMode = (flags >> 10) & 0x01; material.UseTextureOnly = ((flags >> 11) & 0x01) == 1; uint separateBlendMode = (flags >> 12) & 0x01; uint hasIndirectParam = (flags >> 13) & 0x01; uint numProjTexGenParam = (flags >> 14) & 0x03; uint hasFontShadowParam = (flags >> 16) & 0x01; uint texMapOffset = 0x34; uint texMatrixOffset = texMapOffset + (numTexMap * 4); uint texCoordGenOffset = texMatrixOffset + (numTexMatrix * 0x14); uint tevStageOffset = texCoordGenOffset + (numTexCoordGen * 4); uint alphaCompareOffset = tevStageOffset + (numTevStage * 0xC); uint blendModeOffset = alphaCompareOffset + 0x8; reader.Stream.Seek(offset + texMapOffset); for (int i = 0; i < numTexMap; i++) { var entry = new TextureMapEntry(); entry.Index = reader.ReadUInt16(); byte flag1 = reader.ReadByte(); byte flag2 = reader.ReadByte(); entry.WrapS = (WrapMode)(flag1 & 0x3); entry.WrapT = (WrapMode)(flag2 & 0x3); entry.MinFilter = (TextureFilter)((flag1 >> 2) & 0x3); entry.MagFilter = (TextureFilter)((flag2 >> 2) & 0x3); material.TexMapEntries.Add(entry); } reader.Stream.Seek(offset + texMatrixOffset); for (int i = 0; i < numTexMatrix; i++) { var entry = new TextureMatrixEntry(); entry.Translation = new Vector2(reader.ReadSingle(), reader.ReadSingle()); entry.Rotation = reader.ReadSingle(); entry.Scale = new Vector2(reader.ReadSingle(), reader.ReadSingle()); material.TexMatrixEntries.Add(entry); } reader.Stream.Seek(offset + texCoordGenOffset); for (int i = 0; i < numTexCoordGen; i++) { material.TextureCoordGen.Add(reader.ReadSingle()); } // TODO: Find a bclyt with the rest of sections clyt.Materials.Add(material); reader.Stream.PopPosition(); numMaterials--; } }