public ME3ExportEntry(ME3PCCObject pccFile, byte[] importData, uint exportOffset) { pccRef = pccFile; info = (byte[])importData.Clone(); InfoOffset = exportOffset; hasChanged = false; }
/// <summary> /// /// </summary> /// <param name="file"></param> /// <param name="stream"></param> /// <param name="WhichGame"></param> /// <returns></returns> public static IPCCObject CreatePCCObject(string file, MemoryTributary stream, int WhichGame) { IPCCObject pcc; if (WhichGame == 1) pcc = new ME1PCCObject(file, stream); else if (WhichGame == 2) pcc = new ME2PCCObject(file, stream); else if (WhichGame == 3) pcc = new ME3PCCObject(file, stream); else { DebugOutput.PrintLn("WHAT HAVE YOU DONE!! PCCObject creation failed!"); return null; } return pcc; }
/// <summary> /// Creates a PCCObject from a file. /// </summary> /// <param name="file">PCC file to create object from.</param> /// <param name="WhichGame">Game version.</param> /// <returns>IPCCObject from file.</returns> public static IPCCObject CreatePCCObject(string file, int WhichGame) { IPCCObject pcc; // KFreon: Use different methods for each game. if (WhichGame == 1) pcc = new ME1PCCObject(file); else if (WhichGame == 2) pcc = new ME2PCCObject(file); else if (WhichGame == 3) pcc = new ME3PCCObject(file); else { DebugOutput.PrintLn("WHAT HAVE YOU DONE!! PCCObject creation failed!"); return null; } return pcc; }
/// <summary> /// /// </summary> /// <param name="file"></param> /// <param name="stream"></param> /// <param name="WhichGame"></param> /// <returns></returns> public static IPCCObject CreatePCCObject(string file, MemoryStream stream, int WhichGame) { IPCCObject pcc; if (WhichGame == 1) { pcc = new ME1PCCObject(file, stream); } else if (WhichGame == 2) { pcc = new ME2PCCObject(file, stream); } else if (WhichGame == 3) { pcc = new ME3PCCObject(file, stream); } else { DebugOutput.PrintLn("WHAT HAVE YOU DONE!! PCCObject creation failed!"); return(null); } return(pcc); }
/// <summary> /// Creates a PCCObject from a file. /// </summary> /// <param name="file">PCC file to create object from.</param> /// <param name="WhichGame">Game version.</param> /// <returns>IPCCObject from file.</returns> public static IPCCObject CreatePCCObject(string file, int WhichGame) { IPCCObject pcc; // KFreon: Use different methods for each game. if (WhichGame == 1) { pcc = new ME1PCCObject(file); } else if (WhichGame == 2) { pcc = new ME2PCCObject(file); } else if (WhichGame == 3) { pcc = new ME3PCCObject(file); } else { DebugOutput.PrintLn("WHAT HAVE YOU DONE!! PCCObject creation failed!"); return(null); } return(pcc); }
public ME3ImportEntry(ME3PCCObject pccFile, Stream importData) { pccRef = pccFile; data = new byte[ME3ImportEntry.byteSize]; importData.Read(data, 0, data.Length); }
public ME3SaltTexture2D(ME3PCCObject pccObj, int texIdx, String pathBioGame, uint hash = 0) { allPccs = new List<string>(); hasChanged = false; Hash = hash; if (pccObj.isExport(texIdx) && (pccObj.Exports[texIdx].ClassName == className || pccObj.Exports[texIdx].ClassName == class2 || pccObj.Exports[texIdx].ClassName == class3)) { Class = pccObj.Exports[texIdx].ClassName; ME3ExportEntry expEntry = pccObj.Exports[texIdx]; properties = new Dictionary<string, SaltPropertyReader.Property>(); byte[] rawData = (byte[])expEntry.Data.Clone(); int propertiesOffset = SaltPropertyReader.detectStart(pccObj, rawData); headerData = new byte[propertiesOffset]; Buffer.BlockCopy(rawData, 0, headerData, 0, propertiesOffset); pccOffset = expEntry.DataOffset; List<SaltPropertyReader.Property> tempProperties = SaltPropertyReader.getPropList(pccObj, rawData); texName = expEntry.ObjectName; for (int i = 0; i < tempProperties.Count; i++) { SaltPropertyReader.Property property = tempProperties[i]; if (property.Name == "UnpackMin") UnpackNum++; if (!properties.ContainsKey(property.Name)) properties.Add(property.Name, property); switch (property.Name) { case "Format": texFormat = Textures.Methods.ParseFormat(pccObj.Names[property.Value.IntValue].Substring(3)); break; case "TextureFileCacheName": arcName = property.Value.NameValue.Name; break; case "LODGroup": LODGroup = property.Value.NameValue.Name; break; case "None": dataOffset = (uint)(property.offsetval + property.Size); break; } } if (!String.IsNullOrEmpty(arcName)) FullArcPath = GetTexArchive(pathBioGame); // if "None" property isn't found throws an exception if (dataOffset == 0) throw new Exception("\"None\" property not found"); else { imageData = new byte[rawData.Length - dataOffset]; Buffer.BlockCopy(rawData, (int)dataOffset, imageData, 0, (int)(rawData.Length - dataOffset)); } } else throw new Exception("Texture2D " + texIdx + " not found"); pccExpIdx = texIdx; MemoryStream dataStream = new MemoryStream(imageData); // FG: we will move forward with the memorystream (we are reading an export entry for a texture object data inside the pcc) numMipMaps = dataStream.ReadValueU32(); // FG: 1st int32 (4 bytes / 32bits) is number of mipmaps uint count = numMipMaps; privateimgList = new List<ImageInfo>(); ArcDataSize = 0; while (dataStream.Position < dataStream.Length && count > 0) { ImageInfo imgInfo = new ImageInfo(); // FG: store properties in ImageInfo struct (code at top) imgInfo.storageType = (storage)dataStream.ReadValueS32(); // FG: 2nd int32 storage type (see storage types above in enum_struct) imgInfo.uncSize = dataStream.ReadValueS32(); // FG: 3rd int32 uncompressed texture size imgInfo.cprSize = dataStream.ReadValueS32(); // FG: 4th int32 compressed texture size imgInfo.offset = dataStream.ReadValueS32(); // FG: 5th int32 texture offset if (imgInfo.storageType == storage.pccSto) { //imgInfo.offset = (int)(pccOffset + dataOffset); // saving pcc offset as relative to exportdata offset, not absolute imgInfo.offset = (int)dataStream.Position; // saving pcc offset as relative to exportdata offset, not absolute //MessageBox.Show("Pcc class offset: " + pccOffset + "\nimages data offset: " + imgInfo.offset.ToString()); dataStream.Seek(imgInfo.uncSize, SeekOrigin.Current); // FG: if local storage, texture data follows, so advance datastream to after uncompressed_size (pcc storage type only) } else if (imgInfo.storageType == storage.arcCpr || imgInfo.storageType == storage.arcUnc) { ArcDataSize += imgInfo.uncSize; } imgInfo.imgSize = new ImageSize(dataStream.ReadValueU32(), dataStream.ReadValueU32()); // FG: 6th & 7th [or nth and (nth + 1) if local] int32 are width x height privateimgList.Add(imgInfo); // FG: A salty's favorite, add the struct to a list<struct> count--; } // save what remains int remainingBytes = (int)(dataStream.Length - dataStream.Position); footerData = new byte[remainingBytes]; dataStream.Read(footerData, 0, footerData.Length); dataStream.Dispose(); }
public void LoadPcc(IPCCObject pcc, string path) { switch (pcc.GameVersion) { case 1: pcc = new ME1PCCObject(path); break; case 2: pcc = new ME2PCCObject(path); break; case 3: pcc = new ME3PCCObject(path); break; } }
public ME3Texture2D(ME3PCCObject pccObj, int texIdx) { pccRef = pccObj; // check if texIdx is an Export index and a Texture2D class if (pccObj.isExport(texIdx) && (pccObj.Exports[texIdx].ClassName == className)) { ME3ExportEntry expEntry = pccObj.Exports[texIdx]; properties = new Dictionary<string, PropertyReader.Property>(); byte[] rawData = (byte[])expEntry.Data.Clone(); int propertiesOffset = PropertyReader.detectStart(pccObj, rawData); headerData = new byte[propertiesOffset]; Buffer.BlockCopy(rawData, 0, headerData, 0, propertiesOffset); pccOffset = (uint)expEntry.DataOffset; List<PropertyReader.Property> tempProperties = PropertyReader.getPropList(pccObj, rawData); texName = expEntry.ObjectName; for (int i = 0; i < tempProperties.Count; i++) { PropertyReader.Property property = tempProperties[i]; if (!properties.ContainsKey(pccObj.Names[property.Name])) properties.Add(pccObj.Names[property.Name], property); switch (pccObj.Names[property.Name]) { case "Format": texFormat = pccObj.Names[property.Value.IntValue].Substring(3); break; case "TextureFileCacheName": arcName = pccObj.Names[property.Value.IntValue]; break; case "LODGroup": LODGroup = pccObj.Names[property.Value.IntValue]; break; case "None": dataOffset = (uint)(property.offsetval + property.Size); break; } } // if "None" property isn't found throws an exception if (dataOffset == 0) throw new Exception("\"None\" property not found"); else { imageData = new byte[rawData.Length - dataOffset]; Buffer.BlockCopy(rawData, (int)dataOffset, imageData, 0, (int)(rawData.Length - dataOffset)); } } else throw new Exception("Texture2D " + texIdx + " not found"); pccExpIdx = texIdx; MemoryStream dataStream = new MemoryStream(imageData); numMipMaps = dataStream.ReadValueU32(); uint count = numMipMaps; privateImageList = new List<ImageInfo>(); while (dataStream.Position < dataStream.Length && count > 0) { ImageInfo imgInfo = new ImageInfo(); imgInfo.storageType = (storage)dataStream.ReadValueS32(); imgInfo.uncSize = dataStream.ReadValueS32(); imgInfo.cprSize = dataStream.ReadValueS32(); imgInfo.offset = dataStream.ReadValueS32(); if (imgInfo.storageType == storage.pccSto) { //imgInfo.offset = (int)(pccOffset + dataOffset); // saving pcc offset as relative to exportdata offset, not absolute imgInfo.offset = (int)dataStream.Position; // saving pcc offset as relative to exportdata offset, not absolute //MessageBox.Show("Pcc class offset: " + pccOffset + "\nimages data offset: " + imgInfo.offset.ToString()); dataStream.Seek(imgInfo.uncSize, SeekOrigin.Current); } imgInfo.imgSize = new ImageSize(dataStream.ReadValueU32(), dataStream.ReadValueU32()); imgList.Add(imgInfo); count--; } // save what remains /*int remainingBytes = (int)(dataStream.Length - dataStream.Position); footerData = new byte[remainingBytes]; dataStream.Read(footerData, 0, footerData.Length);*/ }
//unused private void replaceImageToolStripMenuItem_Click(object sender, EventArgs e) { int n = listBox1.SelectedIndex; if (n <= 0) return; if (pcc.Exports[n].ClassName != "Texture2D") MessageBox.Show("Not a texture."); else { using (OpenFileDialog ofd = new OpenFileDialog()) { ofd.Filter = "DirectX images|*.dds"; if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { string path = Path.GetDirectoryName(pcc.pccFileName); ME3PCCObject temp = new ME3PCCObject(pcc.pccFileName); ME3SaltTexture2D tex2D = new ME3SaltTexture2D(temp, n, path); string test = tex2D.imgList.Max(t => t.imgSize).ToString(); ImageFile im = KFreonLib.Textures.Creation.LoadAKImageFile(null, ofd.FileName); tex2D.replaceImage(test, im, path); ME3ExportEntry expEntry = temp.Exports[tex2D.pccExpIdx]; expEntry.SetData(tex2D.ToArray(expEntry.DataOffset, temp)); temp.saveToFile(temp.pccFileName); } } } // Reload pcc? }
private void TV1_DoubleClick(object sender, EventArgs e) { TreeNode t = TV1.SelectedNode; if (t == null || t.Parent == null) return; Println("Loading " + t.Text + " ..."); string DLCName = t.Parent.Text; try { if (DLCName == mainPCCFolder) { currentPCC = ME3Directory.cookedPath + t.Text; pcc = new ME3PCCObject(currentPCC); } else { return; } GeneratePccTree(); } catch (Exception ex) { MessageBox.Show("Error:\n" + ex.Message); } }
public void LoadFile(string s) { try { if (!File.Exists(s)) return; pcc = new ME3PCCObject(s); currentPCC = s; GeneratePccTree(); } catch (Exception ex) { MessageBox.Show("Error:\n" + ex.Message); } }
private void CreateFromPCCDiffButton_Click(object sender, EventArgs e) { // KFreon: This is all just renamed stuff from WV's work. No credit to me. // KFreon: Get pcc's IPCCObject basePCC = null; IPCCObject modifiedPCC = null; using (OpenFileDialog ofd = new OpenFileDialog()) { ofd.Filter = "PCC Files|*.pcc"; ofd.Title = "Select base (unmodified) pcc"; if (ofd.ShowDialog() != DialogResult.OK) return; basePCC = new ME3PCCObject(ofd.FileName); ofd.Title = "Select modified pcc"; if (ofd.ShowDialog() != DialogResult.OK) return; modifiedPCC = new ME3PCCObject(ofd.FileName); } // KFreon: Compare PCC's and build script string loc = Path.GetDirectoryName(Application.ExecutablePath); string script = File.ReadAllText(loc + "\\exec\\JobTemplate_Binary2.txt"); if (basePCC.ExportCount != modifiedPCC.ExportCount) throw new NotImplementedException("This is apparently not implemented yet."); // KFreon: Set pcc name var bits = basePCC.pccFileName.Split('\\'); script.Replace("**m1**", bits.Last()); if (basePCC.NameCount != modifiedPCC.NameCount) { StringBuilder names = new StringBuilder(); foreach (var name in modifiedPCC.Names) if (!basePCC.Names.Contains(name)) names.AppendLine("AddName(\"" + name + "\");"); script = script.Replace("**m2**", names.ToString()); } else script = script.Replace("**m2**", "\\ No names to add"); StringBuilder exports = new StringBuilder(); using(MemoryStream data = new MemoryStream()) { for (int i = 0; i < basePCC.ExportCount; i++) { if (!basePCC.Exports[i].Data.SequenceEqual(modifiedPCC.Exports[i].Data)) { int offset = (int)data.Position; data.WriteBytes(modifiedPCC.Exports[i].Data); exports.AppendLine("ReplaceData(" + i + ", " + offset + ", " + modifiedPCC.Exports[i].Data.Length + ");"); } } script = script.Replace("**m3**", exports.ToString()); ModJob job = new ModJob(); job.data = data.ToArray(); job.Name = "PCC Replacement Job for " + bits.Last(); job.Script = script; KFreonLib.Scripting.ModMaker.JobList.Add(job); } Refresh(); }
public void CreateJobsFromPCCDiff(string basePCCName, string modPCCName) { // KFreon: This is all just renamed stuff from WV's work. No credit to me. StatusUpdater.UpdateText("Comparing PCC's..."); // KFreon: Get pcc's IPCCObject basePCC = new ME3PCCObject(basePCCName); IPCCObject modifiedPCC = new ME3PCCObject(modPCCName); // KFreon: Compare PCC's and build script string loc = Path.GetDirectoryName(Application.ExecutablePath); string script = File.ReadAllText(loc + "\\exec\\JobTemplate_Binary2.txt"); // KFreon: Set pcc name var bits = modifiedPCC.pccFileName.Split('\\').ToList(); string filename = bits.Last(); int index = bits.IndexOf("DLC"); if (index > 0) { var dlcpaths = bits.GetRange(index, bits.Count - index); filename = string.Join("\\", dlcpaths); } // KFreon: Filename must contain CookedPCConsole if (!filename.Contains("cookedpcconsole", StringComparison.OrdinalIgnoreCase)) filename = Path.Combine("CookedPCConsole", filename); filename = filename.Replace("\\\\", "\\").Replace("\\", "\\\\"); // KFreon: Need to not end up with \\\\\\\\\\\ or something, so chances are the only thing it would have at this stage is \\\\ so reset that to \\ then expand to \\\\. script = script.Replace("**m2**", filename); if (basePCC.NameCount != modifiedPCC.NameCount) { StringBuilder names = new StringBuilder(); foreach (var name in modifiedPCC.Names) if (!basePCC.Names.Contains(name)) names.AppendLine("names.Add(\"" + name + "\");" + Environment.NewLine); script = script.Replace("// **KF_NAMES", names.ToString()); } int jobCount = 0; for (int i = 0; i < basePCC.ExportCount; i++) { if (modifiedPCC.Exports.Count == i) // KFreon: Not adding Exports just yet. break; if (!basePCC.Exports[i].Data.SequenceEqual(modifiedPCC.Exports[i].Data)) { ModJob job = new ModJob(); job.OriginalScript = script.Replace("**m1**", i.ToString()); job.Script = job.OriginalScript; job.data = modifiedPCC.Exports[i].Data; job.Name = "Binary Replacement Job for " + bits.Last(); job.ExpIDs = new List<int>(); job.ExpIDs.Add(i); job.OrigExpIDs = new List<int>(); job.OrigExpIDs.Add(i); job.PCCs = new List<string>(); job.OrigPCCs = new List<string>(); job.OrigPCCs.Add(modifiedPCC.pccFileName); job.PCCs.Add(modifiedPCC.pccFileName); job.Texname = basePCC.Exports[i].ObjectName; KFreonLib.Scripting.ModMaker.JobList.Add(job); jobCount++; } } if (jobCount > 0) { StatusUpdater.UpdateText("Created Job."); } else { StatusUpdater.UpdateText("No differences found!"); } MainProgBar.ChangeProgressBar(1, 1); ExternalRefresh(); }
public void CopyImgList(ME3SaltTexture2D inTex, ME3PCCObject pcc) { imageData = inTex.imageData; privateimgList = inTex.privateimgList; numMipMaps = inTex.numMipMaps; //Copy Properties byte[] buff; using (MemoryStream tempMem = new MemoryStream()) { tempMem.WriteBytes(headerData); for (int i = 0; i < inTex.properties.Count; i++) { SaltPropertyReader.Property prop = inTex.properties.ElementAt(i).Value; if (prop.Name == "UnpackMin") { for (int j = 0; j < inTex.UnpackNum; j++) { tempMem.WriteValueS64(pcc.addName2(prop.Name)); tempMem.WriteValueS64(pcc.addName2(prop.TypeVal.ToString())); tempMem.WriteValueS32(prop.Size); tempMem.WriteValueS32(j); tempMem.WriteValueF32(prop.Value.FloatValue); } continue; } tempMem.WriteValueS64(pcc.addName2(prop.Name)); if (prop.Name == "None") continue; tempMem.WriteValueS64(pcc.addName2(prop.TypeVal.ToString())); tempMem.WriteValueS64(prop.Size); switch (prop.TypeVal) { case SaltPropertyReader.Type.FloatProperty: tempMem.WriteValueF32(prop.Value.FloatValue); break; case SaltPropertyReader.Type.IntProperty: tempMem.WriteValueS32(prop.Value.IntValue); break; case SaltPropertyReader.Type.NameProperty: tempMem.WriteValueS64(pcc.addName2(prop.Value.StringValue)); // Heff: Modified to handle name references. //var index = pcc.addName2(prop.Value.StringValue); //tempMem.WriteValueS32(index); //tempMem.WriteValueS32(prop.Value.NameValue.count); break; case SaltPropertyReader.Type.ByteProperty: tempMem.WriteValueS64(pcc.addName2(prop.Value.StringValue)); tempMem.WriteValueS32(pcc.addName2(prop.Value.String2)); byte[] footer = new byte[4]; Buffer.BlockCopy(prop.raw, prop.raw.Length - 4, footer, 0, 4); tempMem.WriteBytes(footer); break; case SaltPropertyReader.Type.BoolProperty: tempMem.WriteValueBoolean(prop.Value.Boolereno); break; case SaltPropertyReader.Type.StructProperty: tempMem.WriteValueS64(pcc.addName2(prop.Value.StringValue)); for (int k = 0; k < prop.Size; k++) tempMem.WriteByte((byte)prop.Value.Array[k].IntValue); break; default: throw new NotImplementedException("Property type: " + prop.TypeVal + ", not yet implemented. TELL ME ABOUT THIS!"); } } buff = tempMem.ToArray(); } properties = new Dictionary<string, SaltPropertyReader.Property>(); List<SaltPropertyReader.Property> tempProperties = SaltPropertyReader.ReadProp(pcc, buff, headerData.Length); for (int i = 0; i < tempProperties.Count; i++) { SaltPropertyReader.Property property = tempProperties[i]; if (property.Name == "UnpackMin") UnpackNum++; if (!properties.ContainsKey(property.Name)) properties.Add(property.Name, property); switch (property.Name) { case "Format": texFormat = Textures.Methods.ParseFormat(pcc.Names[property.Value.IntValue].Substring(3)); break; case "TextureFileCacheName": arcName = property.Value.NameValue.Name; break; case "LODGroup": LODGroup = property.Value.NameValue.Name; break; case "None": dataOffset = (uint)(property.offsetval + property.Size); break; } } // if "None" property isn't found throws an exception if (dataOffset == 0) throw new Exception("\"None\" property not found"); }
public ME3ImportEntry(ME3PCCObject pccFile, byte[] importData) { pccRef = pccFile; data = (byte[])importData.Clone(); }
public byte[] ToArray(uint pccExportDataOffset, ME3PCCObject pcc) { using (MemoryStream tempStream = new MemoryStream()) { tempStream.WriteBytes(headerData); // Whilst testing get rid of this // Heff: Seems like the shadowmap was the best solution in most cases, // adding an exception for known problematic animated textures for now. // (See popup in tpftools) if (properties.ContainsKey("LODGroup")) properties["LODGroup"].Value.String2 = "TEXTUREGROUP_Shadowmap"; else { tempStream.WriteValueS64(pcc.addName2("LODGroup")); tempStream.WriteValueS64(pcc.addName2("ByteProperty")); tempStream.WriteValueS64(8); tempStream.WriteValueS64(pcc.addName2("TextureGroup")); tempStream.WriteValueS64(pcc.addName2("TEXTUREGROUP_Shadowmap")); } foreach (KeyValuePair<string, SaltPropertyReader.Property> kvp in properties) { SaltPropertyReader.Property prop = kvp.Value; if (prop.Name == "UnpackMin") { for (int i = 0; i < UnpackNum; i++) { tempStream.WriteValueS64(pcc.addName2(prop.Name)); tempStream.WriteValueS64(pcc.addName2(prop.TypeVal.ToString())); tempStream.WriteValueS32(prop.Size); tempStream.WriteValueS32(i); tempStream.WriteValueF32(prop.Value.FloatValue); } continue; } tempStream.WriteValueS64(pcc.addName2(prop.Name)); if (prop.Name == "None") continue; tempStream.WriteValueS64(pcc.addName2(prop.TypeVal.ToString())); tempStream.WriteValueS64(prop.Size); switch (prop.TypeVal) { case SaltPropertyReader.Type.FloatProperty: tempStream.WriteValueF32(prop.Value.FloatValue); break; case SaltPropertyReader.Type.IntProperty: tempStream.WriteValueS32(prop.Value.IntValue); break; case SaltPropertyReader.Type.NameProperty: tempStream.WriteValueS64(pcc.addName2(prop.Value.StringValue)); // Heff: Modified to handle name references. //var nameIndex = pcc.addName2(prop.Value.StringValue); //tempStream.WriteValueS32(nameIndex); //tempStream.WriteValueS32(prop.Value.NameValue.count); break; case SaltPropertyReader.Type.ByteProperty: tempStream.WriteValueS64(pcc.addName2(prop.Value.StringValue)); tempStream.WriteValueS64(pcc.addName2(prop.Value.String2)); // Heff: Modified to handle name references. //var valueIndex = pcc.addName2(prop.Value.String2); //tempStream.WriteValueS32(valueIndex); //tempStream.WriteValueS32(prop.Value.NameValue.count); //tempStream.WriteValueS32(pcc.addName2(prop.Value.String2)); //byte[] footer = new byte[4]; //Buffer.BlockCopy(prop.raw, prop.raw.Length - 4, footer, 0, 4); //tempStream.WriteBytes(footer); break; case SaltPropertyReader.Type.BoolProperty: tempStream.WriteValueBoolean(prop.Value.Boolereno); break; case SaltPropertyReader.Type.StructProperty: tempStream.WriteValueS64(pcc.addName2(prop.Value.StringValue)); for (int i = 0; i < prop.Size; i++) tempStream.WriteByte((byte)prop.Value.Array[i].IntValue); break; default: throw new NotImplementedException("Property type: " + prop.TypeVal + ", not yet implemented. TELL ME ABOUT THIS!"); } } //Remove empty textures List<ImageInfo> tempList = new List<ImageInfo>(); foreach (ImageInfo imgInfo in privateimgList) { if (imgInfo.storageType != storage.empty) tempList.Add(imgInfo); } privateimgList = tempList; numMipMaps = (uint)privateimgList.Count; tempStream.WriteValueU32(numMipMaps); foreach (ImageInfo imgInfo in privateimgList) { tempStream.WriteValueS32((int)imgInfo.storageType); tempStream.WriteValueS32(imgInfo.uncSize); tempStream.WriteValueS32(imgInfo.cprSize); if (imgInfo.storageType == storage.pccSto) { tempStream.WriteValueS32((int)(imgInfo.offset + pccExportDataOffset + dataOffset)); tempStream.Write(imageData, imgInfo.offset, imgInfo.uncSize); } else tempStream.WriteValueS32(imgInfo.offset); tempStream.WriteValueU32(imgInfo.imgSize.width); tempStream.WriteValueU32(imgInfo.imgSize.height); } //// Texture2D footer, 24 bytes size - changed to 20 //tempStream.Write(imageData, imageData.Length - 20, 20); tempStream.WriteBytes(footerData); return tempStream.ToArray(); } #region Unused Code /* bool lodExists = false; foreach (KeyValuePair<string, PropertyReader.Property> kvp in properties) { PropertyReader.Property property = kvp.Value; if (kvp.Key == "LODGroup") { lodExists = true; break; } } MemoryStream buffer = new MemoryStream(); buffer.Write(headerData, 0, headerData.Length); if (lodExists) { // extracting values from LODGroup Property PropertyReader.Property LODGroup = properties["LODGroup"]; string textureGroupName = pcc.Names[LODGroup.Value.IntValue]; bool nameExists = false; string newTextureGroupName = "TEXTUREGROUP_Shadowmap"; if (String.Compare(newTextureGroupName, textureGroupName) != 0) { textureGroupName = newTextureGroupName; if (!pcc.Names.Exists(name => name == newTextureGroupName)) pcc.Names.Add(newTextureGroupName); using (MemoryStream rawStream = new MemoryStream(LODGroup.raw)) { rawStream.Seek(32, SeekOrigin.Begin); rawStream.WriteValueS32(pcc.Names.FindIndex(name => name == newTextureGroupName)); rawStream.WriteValueS32(0); properties["LODGroup"].raw = rawStream.ToArray(); } } else nameExists = true; //MemoryStream buffer = new MemoryStream(); //buffer.Write(headerData, 0, headerData.Length); foreach (KeyValuePair<string, PropertyReader.Property> kvp in properties) { PropertyReader.Property property = kvp.Value; if (kvp.Key == "LODBias") continue; if (kvp.Key == "InternalFormatLODBias") continue; if (kvp.Key == "LODGroup" && nameExists == false) { int name; if (!nameExists) name = pcc.Names.Count - 1; //Warranty Voiders Name redirect hack^^ else name = LODGroup.Value.IntValue; ME3_HR_Patch.Helper.BitConverter.IsLittleEndian = true; byte[] buff = ME3_HR_Patch.Helper.BitConverter.GetBytes(name); for (int i = 0; i < 4; i++) property.raw[i + 24] = buff[i]; } buffer.Write(property.raw, 0, property.raw.Length); if (kvp.Key == "UnpackMin") { buffer.Write(property.raw, 0, property.raw.Length); buffer.Write(property.raw, 0, property.raw.Length); } } } else { //MemoryStream buffer = new MemoryStream(); //buffer.Write(headerData, 0, headerData.Length); int lodID = pcc.findName("LODGroup"); if (lodID == -1) { pcc.addName("LODGroup"); lodID = pcc.Names.Count - 1; } buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes(lodID)); buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes((int)0)); lodID = pcc.findName("ByteProperty"); buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes(lodID)); buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes((int)0)); //Write an int buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes((int)8)); buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes((int)0)); lodID = pcc.findName("TextureGroup"); if (lodID == -1) { pcc.addName("TextureGroup"); lodID = pcc.Names.Count - 1; } buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes(lodID)); buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes((int)0)); lodID = pcc.findName("TEXTUREGROUP_Shadowmap"); if (lodID == -1) { pcc.addName("TEXTUREGROUP_Shadowmap"); lodID = pcc.Names.Count - 1; } buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes(lodID)); buffer.WriteBytes(ME3_HR_Patch.Helper.BitConverter.GetBytes((int)0)); foreach (KeyValuePair<string, PropertyReader.Property> kvp in properties) { PropertyReader.Property property = kvp.Value; if (kvp.Key == "LODBias") continue; if (kvp.Key == "InternalFormatLODBias") continue; if (kvp.Key == "LODGroup") { int name = pcc.Names.Count - 1; //Warranty Voiders Name redirect hack^^ ME3_HR_Patch.Helper.BitConverter.IsLittleEndian = true; byte[] buff = ME3_HR_Patch.Helper.BitConverter.GetBytes(name); for (int i = 0; i < 4; i++) property.raw[i + 24] = buff[i]; } buffer.Write(property.raw, 0, property.raw.Length); if (kvp.Key == "UnpackMin") { buffer.Write(property.raw, 0, property.raw.Length); buffer.Write(property.raw, 0, property.raw.Length); } } } buffer.WriteValueU32(numMipMaps); foreach (ImageInfo imgInfo in imgList) { buffer.WriteValueS32((int)imgInfo.storageType); buffer.WriteValueS32(imgInfo.uncSize); buffer.WriteValueS32(imgInfo.cprSize); if (imgInfo.storageType == storage.pccSto) { buffer.WriteValueS32((int)(imgInfo.offset + pccExportDataOffset + dataOffset)); buffer.Write(imageData, imgInfo.offset, imgInfo.uncSize); } else buffer.WriteValueS32(imgInfo.offset); buffer.WriteValueU32(imgInfo.imgSize.width); buffer.WriteValueU32(imgInfo.imgSize.height); } // Texture2D footer, 24 bytes size buffer.Write(imageData, imageData.Length - 24, 24); byte[] rawData = buffer.ToArray(); return rawData; */ #endregion }