public void extractTextureToDDS(string outputFile, string packagePath, int exportID) { Package package = new Package(packagePath); Texture texture = new Texture(package, exportID, package.getExportData(exportID)); while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)) { texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty)); } List <DDSImage.MipMap> mipmaps = new List <DDSImage.MipMap>(); DDSFormat format = DDSImage.convertFormat(texture.properties.getProperty("Format").valueName); for (int i = 0; i < texture.mipMapsList.Count; i++) { byte[] data = texture.getMipMapDataByIndex(i); if (data == null) { MessageBox.Show("Failed to extract to DDS file. Broken game files!"); return; } mipmaps.Add(new DDSImage.MipMap(data, format, texture.mipMapsList[i].width, texture.mipMapsList[i].height)); } DDSImage dds = new DDSImage(mipmaps); if (File.Exists(outputFile)) { File.Delete(outputFile); } using (FileStream fs = new FileStream(outputFile, FileMode.CreateNew, FileAccess.Write)) { dds.SaveDDSImage(fs); } }
public void extractTextureToPng(string outputFile, string packagePath, int exportID) { Package package = new Package(packagePath); Texture texture = new Texture(package, exportID, package.getExportData(exportID)); DDSFormat format = DDSImage.convertFormat(texture.properties.getProperty("Format").valueName); Texture.MipMap mipmap = texture.getTopMipmap(); byte[] data = texture.getTopImageData(); if (data == null) { MessageBox.Show("Failed to extract to PNG file. Broken game files!"); return; } PngBitmapEncoder image = DDSImage.ToPng(data, format, mipmap.width, mipmap.height); if (File.Exists(outputFile)) { File.Delete(outputFile); } using (FileStream fs = new FileStream(outputFile, FileMode.CreateNew, FileAccess.Write)) { image.Save(fs); } }
static private string convertDataModtoMem(string inputDir, string memFilePath) { string errors = ""; string[] files = null; Console.WriteLine("Mods conversion started..."); List <string> list = Directory.GetFiles(inputDir, "*.tpf").Where(item => item.EndsWith(".tpf", StringComparison.OrdinalIgnoreCase)).ToList(); list.AddRange(Directory.GetFiles(inputDir, "*.mod").Where(item => item.EndsWith(".mod", StringComparison.OrdinalIgnoreCase))); list.AddRange(Directory.GetFiles(inputDir, "*.dds").Where(item => item.EndsWith(".dds", StringComparison.OrdinalIgnoreCase))); list.Sort(); files = list.ToArray(); int result; string fileName = ""; uint dstLen = 0; string[] ddsList = null; ulong numEntries = 0; List <TexExplorer.BinaryMod> mods = new List <TexExplorer.BinaryMod>(); foreach (string file in files) { if (file.EndsWith(".mod", StringComparison.OrdinalIgnoreCase)) { try { using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { string package = ""; int len = fs.ReadInt32(); string version = fs.ReadStringASCII(len); // version if (version.Length < 5) // legacy .mod { fs.SeekBegin(); } numEntries = fs.ReadUInt32(); for (uint i = 0; i < numEntries; i++) { TexExplorer.BinaryMod mod = new TexExplorer.BinaryMod(); len = fs.ReadInt32(); string desc = fs.ReadStringASCII(len); // description len = fs.ReadInt32(); string scriptLegacy = fs.ReadStringASCII(len); string path = ""; if (desc.Contains("Binary Replacement")) { try { Misc.ParseME3xBinaryScriptMod(scriptLegacy, ref package, ref mod.exportId, ref path); if (mod.exportId == -1 || package == "" || path == "") { throw new Exception(); } } catch { len = fs.ReadInt32(); fs.Skip(len); errors += "Skipping not compatible content, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } mod.packagePath = GameData.RelativeGameData(Path.Combine(path, package)); mod.binaryMod = true; len = fs.ReadInt32(); mod.data = fs.ReadToBuffer(len); } else { string textureName = desc.Split(' ').Last(); FoundTexture f; try { f = Misc.ParseLegacyMe3xScriptMod(textures, scriptLegacy, textureName); mod.textureCrc = f.crc; if (mod.textureCrc == 0) { throw new Exception(); } } catch { len = fs.ReadInt32(); fs.Skip(len); errors += "Skipping not compatible content, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } textureName = f.name; mod.textureName = textureName; mod.binaryMod = false; len = fs.ReadInt32(); mod.data = fs.ReadToBuffer(len); DDSImage image = new DDSImage(new MemoryStream(mod.data)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture has not all the required mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } Package pkg = new Package(GameData.GamePath + f.list[0].path); Texture texture = new Texture(pkg, f.list[0].exportID, pkg.getExportData(f.list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture must have mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture has wrong aspect ratio, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } } mods.Add(mod); } } } catch { errors += "Mod is not compatible: " + file + Environment.NewLine; continue; } } else if (file.EndsWith(".tpf", StringComparison.OrdinalIgnoreCase)) { IntPtr handle = IntPtr.Zero; try { byte[] buffer = File.ReadAllBytes(file); handle = ZlibHelper.Zip.Open(buffer, ref numEntries, 1); if (ZlibHelper.Zip.LocateFile(handle, "texmod.def") != 0) { throw new Exception(); } result = ZlibHelper.Zip.GetCurrentFileInfo(handle, ref fileName, ref dstLen); if (result != 0) { throw new Exception(); } byte[] listText = new byte[dstLen]; result = ZlibHelper.Zip.ReadCurrentFile(handle, listText, dstLen); if (result != 0) { throw new Exception(); } ddsList = Encoding.ASCII.GetString(listText).Trim('\0').Replace("\r", "").TrimEnd('\n').Split('\n'); result = ZlibHelper.Zip.GoToFirstFile(handle); if (result != 0) { throw new Exception(); } for (uint i = 0; i < numEntries; i++) { TexExplorer.BinaryMod mod = new TexExplorer.BinaryMod(); try { uint crc = 0; result = ZlibHelper.Zip.GetCurrentFileInfo(handle, ref fileName, ref dstLen); if (result != 0) { throw new Exception(); } string filename = Path.GetFileName(fileName); foreach (string dds in ddsList) { string ddsFile = dds.Split('|')[1]; if (ddsFile.ToLowerInvariant() != filename.ToLowerInvariant()) { continue; } crc = uint.Parse(dds.Split('|')[0].Substring(2), System.Globalization.NumberStyles.HexNumber); break; } if (crc == 0) { if (filename != "texmod.def") { errors += "Skipping file: " + filename + " not founded in texmod.def, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; } ZlibHelper.Zip.GoToNextFile(handle); continue; } List <FoundTexture> foundCrcList = textures.FindAll(s => s.crc == crc); if (foundCrcList.Count == 0) { errors += "Texture skipped. File " + filename + string.Format(" - 0x{0:X8}", crc) + " is not present in your game setup - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } string textureName = foundCrcList[0].name; mod.textureName = textureName; mod.binaryMod = false; mod.textureCrc = crc; mod.data = new byte[dstLen]; result = ZlibHelper.Zip.ReadCurrentFile(handle, mod.data, dstLen); if (result != 0) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + ", skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } uint tag = BitConverter.ToUInt32(mod.data, 0); if (tag != 0x20534444) // DDS { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture is not in DDS format, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } DDSImage image = new DDSImage(new MemoryStream(mod.data)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture has not all the required mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } Package pkg = new Package(GameData.GamePath + foundCrcList[0].list[0].path); Texture texture = new Texture(pkg, foundCrcList[0].list[0].exportID, pkg.getExportData(foundCrcList[0].list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture must have mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture has wrong aspect ratio, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } mods.Add(mod); } catch { errors += "Skipping not compatible content, entry: " + (i + 1) + " file: " + fileName + " - mod: " + file + Environment.NewLine; } ZlibHelper.Zip.GoToNextFile(handle); } ZlibHelper.Zip.Close(handle); handle = IntPtr.Zero; } catch { errors += "Mod is not compatible: " + file + Environment.NewLine; if (handle != IntPtr.Zero) { ZlibHelper.Zip.Close(handle); } handle = IntPtr.Zero; continue; } } else if (file.EndsWith(".dds", StringComparison.OrdinalIgnoreCase)) { TexExplorer.BinaryMod mod = new TexExplorer.BinaryMod(); string filename = Path.GetFileNameWithoutExtension(file).ToLowerInvariant(); if (!filename.Contains("0x")) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } int idx = filename.IndexOf("0x"); if (filename.Length - idx < 10) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } uint crc; string crcStr = filename.Substring(idx + 2, 8); try { crc = uint.Parse(crcStr, System.Globalization.NumberStyles.HexNumber); } catch { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } List <FoundTexture> foundCrcList = textures.FindAll(s => s.crc == crc); if (foundCrcList.Count == 0) { errors += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; continue; } using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { mod.data = fs.ReadToBuffer((int)fs.Length); DDSImage image = new DDSImage(new MemoryStream(mod.data)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; continue; } Package pkg = new Package(GameData.GamePath + foundCrcList[0].list[0].path); Texture texture = new Texture(pkg, foundCrcList[0].list[0].exportID, pkg.getExportData(foundCrcList[0].list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; continue; } mod.textureName = foundCrcList[0].name; mod.binaryMod = false; mod.textureCrc = crc; mods.Add(mod); } } } if (mods.Count == 0) { Console.WriteLine("Mods conversion failed"); return(errors); } Console.WriteLine("Saving to MEM file... " + memFilePath); List <MipMaps.FileMod> modFiles = new List <MipMaps.FileMod>(); FileStream outFs; if (File.Exists(memFilePath)) { File.Delete(memFilePath); } using (outFs = new FileStream(memFilePath, FileMode.Create, FileAccess.Write)) { outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(0); // filled later for (int l = 0; l < mods.Count; l++) { MipMaps.FileMod fileMod = new MipMaps.FileMod(); Stream dst = MipMaps.compressData(mods[l].data); dst.SeekBegin(); fileMod.offset = outFs.Position; fileMod.size = dst.Length; if (mods[l].binaryMod) { fileMod.tag = MipMaps.FileBinaryTag; fileMod.name = Path.GetFileNameWithoutExtension(mods[l].packagePath) + "_" + mods[l].exportId + ".bin"; outFs.WriteInt32(mods[l].exportId); outFs.WriteStringASCIINull(mods[l].packagePath); } else { fileMod.tag = MipMaps.FileTextureTag; fileMod.name = mods[l].textureName + string.Format("_0x{0:X8}", mods[l].textureCrc) + ".dds"; outFs.WriteStringASCIINull(mods[l].textureName); outFs.WriteUInt32(mods[l].textureCrc); } outFs.WriteFromStream(dst, dst.Length); modFiles.Add(fileMod); } long pos = outFs.Position; outFs.SeekBegin(); outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(pos); outFs.JumpTo(pos); outFs.WriteUInt32((uint)GameData.gameType); outFs.WriteInt32(modFiles.Count); for (int i = 0; i < modFiles.Count; i++) { outFs.WriteUInt32(modFiles[i].tag); outFs.WriteStringASCIINull(modFiles[i].name); outFs.WriteInt64(modFiles[i].offset); outFs.WriteInt64(modFiles[i].size); } } Console.WriteLine("Mods conversion process completed"); return(errors); }
public string createTextureMod(string inDir, string outFile, List <FoundTexture> textures, MainWindow mainWindow, ref string log) { string errors = ""; int count = 0; List <string> files = Directory.GetFiles(inDir, "*.dds").Where(item => item.EndsWith(".dds", StringComparison.OrdinalIgnoreCase)).ToList(); files.Sort(); List <FileMod> modFiles = new List <FileMod>(); using (FileStream outFs = new FileStream(outFile, FileMode.Create, FileAccess.Write)) { outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(0); // files info offset - filled later for (int n = 0; n < files.Count(); n++) { string file = files[n]; if (mainWindow != null) { mainWindow.updateStatusLabel("Creating MOD: " + Path.GetFileName(outFile)); mainWindow.updateStatusLabel2("Texture " + (n + 1) + " of " + files.Count() + ", File: " + Path.GetFileName(file)); } string filename = Path.GetFileNameWithoutExtension(file).ToLowerInvariant(); if (!filename.Contains("0x")) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } int idx = filename.IndexOf("0x"); if (filename.Length - idx < 10) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } uint crc; string crcStr = filename.Substring(idx + 2, 8); try { crc = uint.Parse(crcStr, System.Globalization.NumberStyles.HexNumber); } catch { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (_0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (_0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } List <FoundTexture> foundCrcList = textures.FindAll(s => s.crc == crc); if (foundCrcList.Count == 0) { errors += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; log += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; continue; } int savedCount = count; using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { byte[] src = fs.ReadToBuffer((int)fs.Length); DDSImage image = new DDSImage(new MemoryStream(src)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; continue; } Package pkg = new Package(GameData.GamePath + foundCrcList[0].list[0].path); Texture texture = new Texture(pkg, foundCrcList[0].list[0].exportID, pkg.getExportData(foundCrcList[0].list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; continue; } Stream dst = compressData(src); dst.SeekBegin(); FileMod fileMod = new FileMod(); fileMod.tag = FileTextureTag; fileMod.name = Path.GetFileName(file); fileMod.offset = outFs.Position; fileMod.size = dst.Length; count++; modFiles.Add(fileMod); outFs.WriteStringASCIINull(foundCrcList[0].name); outFs.WriteUInt32(crc); outFs.WriteFromStream(dst, dst.Length); } if (count == savedCount) { continue; } } long pos = outFs.Position; outFs.SeekBegin(); outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(pos); outFs.JumpTo(pos); outFs.WriteUInt32((uint)GameData.gameType); outFs.WriteInt32(modFiles.Count); for (int i = 0; i < modFiles.Count; i++) { outFs.WriteUInt32(modFiles[i].tag); outFs.WriteStringASCIINull(modFiles[i].name); outFs.WriteInt64(modFiles[i].offset); outFs.WriteInt64(modFiles[i].size); } } if (count == 0) { errors += "There are no texture files in " + inDir + ", mod not generated." + Environment.NewLine; log += "There are no texture files in " + inDir + ", mod not generated." + Environment.NewLine; File.Delete(outFile); } return(errors); }
public string replaceTexture(DDSImage image, List <MatchedTexture> list, CachePackageMgr cachePackageMgr, string textureName, uint crc) { List <Texture> masterTextures = new List <Texture>(); Texture arcTexture = null, cprTexture = null; string errors = ""; for (int n = 0; n < list.Count; n++) { MatchedTexture nodeTexture = list[n]; Package package = cachePackageMgr.OpenPackage(GameData.GamePath + nodeTexture.path); Texture texture = new Texture(package, nodeTexture.exportID, package.getExportData(nodeTexture.exportID)); while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)) { texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty)); } bool master = true; if (GameData.gameType == MeType.ME1_TYPE) { if (texture.packageName.ToLowerInvariant() != Path.GetFileNameWithoutExtension(package.packageFile.Name).ToLowerInvariant()) { master = false; if (!masterTextures.Exists(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant())) { errors += "Error in texture: " + textureName + " Broken game file: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine; continue; } } } if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + textureName + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; break; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + textureName + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; break; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + textureName + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; break; } // remove lower mipmaps from source image which not exist in game data for (int t = 0; t < image.mipMaps.Count(); t++) { if (image.mipMaps[t].origWidth <= texture.mipMapsList[0].width && image.mipMaps[t].origHeight <= texture.mipMapsList[0].height && texture.mipMapsList.Count > 1) { if (!texture.mipMapsList.Exists(m => m.width == image.mipMaps[t].origWidth && m.height == image.mipMaps[t].origHeight)) { image.mipMaps.RemoveAt(t--); } } } bool skip = false; // reuse lower mipmaps from game data which not exist in source image for (int t = 0; t < texture.mipMapsList.Count; t++) { if (texture.mipMapsList[t].width <= image.mipMaps[0].origWidth && texture.mipMapsList[t].height <= image.mipMaps[0].origHeight) { if (!image.mipMaps.Exists(m => m.origWidth == texture.mipMapsList[t].width && m.origHeight == texture.mipMapsList[t].height)) { byte[] data = texture.getMipMapData(texture.mipMapsList[t]); if (data == null) { errors += "Error in game data: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine; skip = true; break; } DDSImage.MipMap mipmap = new DDSImage.MipMap(data, ddsFormat, texture.mipMapsList[t].width, texture.mipMapsList[t].height); image.mipMaps.Add(mipmap); } } } if (skip) { continue; } package.DisposeCache(); bool triggerCacheArc = false, triggerCacheCpr = false; string archiveFile = ""; byte[] origGuid = new byte[16]; if (texture.properties.exists("TextureFileCacheName")) { Array.Copy(texture.properties.getProperty("TFCFileGuid").valueStruct, origGuid, 16); string archive = texture.properties.getProperty("TextureFileCacheName").valueName; archiveFile = Path.Combine(GameData.MainData, archive + ".tfc"); if (nodeTexture.path.ToLowerInvariant().Contains("\\dlc")) { string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(GameData.GamePath + nodeTexture.path), archive + ".tfc"); if (File.Exists(DLCArchiveFile)) { archiveFile = DLCArchiveFile; } else if (!File.Exists(archiveFile)) { List <string> files = Directory.GetFiles(GameData.bioGamePath, archive + ".tfc", SearchOption.AllDirectories).Where(item => item.EndsWith(".tfc", StringComparison.OrdinalIgnoreCase)).ToList(); if (files.Count == 0) { archiveFile = Path.Combine(GameData.MainData, "Textures.tfc"); } else if (files.Count == 1) { archiveFile = files[0]; } else { throw new Exception(""); } } } long fileLength = new FileInfo(archiveFile).Length; if (fileLength + 0x5000000 > 0x80000000) { archiveFile = ""; foreach (TFCTexture newGuid in guids) { archiveFile = Path.Combine(GameData.MainData, newGuid.name + ".tfc"); if (!File.Exists(archiveFile)) { texture.properties.setNameValue("TextureFileCacheName", newGuid.name); texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid); using (FileStream fs = new FileStream(archiveFile, FileMode.CreateNew, FileAccess.Write)) { fs.WriteFromBuffer(newGuid.guid); } break; } else { fileLength = new FileInfo(archiveFile).Length; if (fileLength + 0x5000000 < 0x80000000) { texture.properties.setNameValue("TextureFileCacheName", newGuid.name); texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid); break; } } archiveFile = ""; } if (archiveFile == "") { throw new Exception("No free TFC texture file!"); } } } List <Texture.MipMap> mipmaps = new List <Texture.MipMap>(); for (int m = 0; m < image.mipMaps.Count(); m++) { Texture.MipMap mipmap = new Texture.MipMap(); mipmap.width = image.mipMaps[m].origWidth; mipmap.height = image.mipMaps[m].origHeight; if (texture.existMipmap(mipmap.width, mipmap.height)) { mipmap.storageType = texture.getMipmap(mipmap.width, mipmap.height).storageType; } else { mipmap.storageType = texture.getTopMipmap().storageType; if (GameData.gameType == MeType.ME1_TYPE && master == false) { if (mipmap.storageType == Texture.StorageTypes.pccUnc || mipmap.storageType == Texture.StorageTypes.pccLZO || mipmap.storageType == Texture.StorageTypes.pccZlib) { mipmap.storageType = Texture.StorageTypes.extLZO; } } else if (GameData.gameType == MeType.ME2_TYPE || GameData.gameType == MeType.ME3_TYPE) { if (texture.properties.exists("TextureFileCacheName") && texture.mipMapsList.Count > 1) { if (texture.mipMapsList.Count < 6) { mipmap.storageType = Texture.StorageTypes.pccUnc; if (!texture.properties.exists("NeverStream")) { if (package.existsNameId("NeverStream")) { texture.properties.addBoolValue("NeverStream", true); } else { goto skip; } } } else { if (GameData.gameType == MeType.ME2_TYPE) { mipmap.storageType = Texture.StorageTypes.extLZO; } else { mipmap.storageType = Texture.StorageTypes.extZlib; } } } } } if (mipmap.storageType == Texture.StorageTypes.extLZO) { mipmap.storageType = Texture.StorageTypes.extZlib; } if (mipmap.storageType == Texture.StorageTypes.pccLZO) { mipmap.storageType = Texture.StorageTypes.pccZlib; } mipmap.uncompressedSize = image.mipMaps[m].data.Length; if (GameData.gameType == MeType.ME1_TYPE) { if (mipmap.storageType == Texture.StorageTypes.pccLZO || mipmap.storageType == Texture.StorageTypes.pccZlib) { if (master) { mipmap.newData = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType); } else { mipmap.newData = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].newData; } mipmap.compressedSize = mipmap.newData.Length; } if (mipmap.storageType == Texture.StorageTypes.pccUnc) { mipmap.compressedSize = mipmap.uncompressedSize; mipmap.newData = image.mipMaps[m].data; } if ((mipmap.storageType == Texture.StorageTypes.extLZO || mipmap.storageType == Texture.StorageTypes.extZlib) && master == false) { mipmap.compressedSize = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].compressedSize; mipmap.dataOffset = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].dataOffset; } } else { if (mipmap.storageType == Texture.StorageTypes.extZlib || mipmap.storageType == Texture.StorageTypes.extLZO) { if (cprTexture == null || (cprTexture != null && mipmap.storageType != cprTexture.mipMapsList[m].storageType)) { mipmap.newData = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType); triggerCacheCpr = true; } else { if (cprTexture.mipMapsList[m].width != mipmap.width || cprTexture.mipMapsList[m].height != mipmap.height) { throw new Exception(); } mipmap.newData = cprTexture.mipMapsList[m].newData; } mipmap.compressedSize = mipmap.newData.Length; } if (mipmap.storageType == Texture.StorageTypes.pccUnc || mipmap.storageType == Texture.StorageTypes.extUnc) { mipmap.compressedSize = mipmap.uncompressedSize; mipmap.newData = image.mipMaps[m].data; } if (mipmap.storageType == Texture.StorageTypes.extZlib || mipmap.storageType == Texture.StorageTypes.extLZO || mipmap.storageType == Texture.StorageTypes.extUnc) { if (arcTexture == null || !StructuralComparisons.StructuralEqualityComparer.Equals( arcTexture.properties.getProperty("TFCFileGuid").valueStruct, texture.properties.getProperty("TFCFileGuid").valueStruct)) { triggerCacheArc = true; Texture.MipMap oldMipmap = texture.getMipmap(mipmap.width, mipmap.height); if (StructuralComparisons.StructuralEqualityComparer.Equals(origGuid, texture.properties.getProperty("TFCFileGuid").valueStruct) && oldMipmap.width != 0 && mipmap.newData.Length <= oldMipmap.compressedSize) { try { using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write)) { fs.JumpTo(oldMipmap.dataOffset); mipmap.dataOffset = oldMipmap.dataOffset; fs.WriteFromBuffer(mipmap.newData); } } catch { throw new Exception("Problem with access to TFC file: " + archiveFile); } } else { try { using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write)) { fs.SeekEnd(); mipmap.dataOffset = (uint)fs.Position; fs.WriteFromBuffer(mipmap.newData); } } catch { throw new Exception("Problem with access to TFC file: " + archiveFile); } } } else { if (arcTexture.mipMapsList[m].width != mipmap.width || arcTexture.mipMapsList[m].height != mipmap.height) { throw new Exception(); } mipmap.dataOffset = arcTexture.mipMapsList[m].dataOffset; } } } mipmap.width = image.mipMaps[m].width; mipmap.height = image.mipMaps[m].height; mipmaps.Add(mipmap); if (texture.mipMapsList.Count() == 1) { break; } } texture.replaceMipMaps(mipmaps); texture.properties.setIntValue("SizeX", texture.mipMapsList.First().width); texture.properties.setIntValue("SizeY", texture.mipMapsList.First().height); if (texture.properties.exists("MipTailBaseIdx")) { texture.properties.setIntValue("MipTailBaseIdx", texture.mipMapsList.Count() - 1); } if (GameData.gameType == MeType.ME1_TYPE && crc == 0x39A26907) { if (!texture.properties.exists("LODGroup")) { texture.properties.addByteValue("LODGroup", "TEXTUREGROUP_Character", 1025); } else { texture.properties.setByteValue("LODGroup", "TEXTUREGROUP_Character", 1025); } } using (MemoryStream newData = new MemoryStream()) { newData.WriteFromBuffer(texture.properties.toArray()); newData.WriteFromBuffer(texture.toArray(0)); // filled later package.setExportData(nodeTexture.exportID, newData.ToArray()); } using (MemoryStream newData = new MemoryStream()) { newData.WriteFromBuffer(texture.properties.toArray()); newData.WriteFromBuffer(texture.toArray(package.exportsTable[nodeTexture.exportID].dataOffset + (uint)newData.Position)); package.setExportData(nodeTexture.exportID, newData.ToArray()); } if (GameData.gameType == MeType.ME1_TYPE) { if (master) { masterTextures.Add(texture); } } else { if (triggerCacheCpr) { cprTexture = texture; } if (triggerCacheArc) { arcTexture = texture; } } skip: package = null; } masterTextures = null; arcTexture = cprTexture = null; return(errors); }