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