public string Extract(BundleFileExtractArgs e) { var newpath = Path.ChangeExtension(e.FileName, "dds"); var ext = Path.GetExtension(e.FileName); // create new directory and delete existing file Directory.CreateDirectory(Path.GetDirectoryName(newpath) ?? ""); if (File.Exists(newpath)) { File.Delete(newpath); } // extract to dds using (var output = new FileStream(newpath, FileMode.Create, FileAccess.Write)) { Extract(output); } // don't convert if user extract extension is already dds if (e.Extension == EUncookExtension.dds) { return(newpath); } // don't convert w2cube cubemaps if (ext == ".w2cube") { return(newpath); } var extractext = e.Extension; // do not convert pngs, jpgs and dds if (!(ext == ".dds" || ext == ".w2l")) { switch (ext) { case ".png": extractext = EUncookExtension.png; break; case ".jpg": extractext = EUncookExtension.jpg; break; } //convert var fi = new FileInfo(newpath); if (fi.Exists) { TexconvWrapper.Convert(Path.GetDirectoryName(newpath), newpath, (Common.Tools.DDS.EUncookExtension)extractext); } // delete old DDS fi.Delete(); } return(newpath); }
/// <summary> /// Extracts all Files to the specified directory. /// </summary> /// <param name="outDir"></param> /// <returns></returns> public int ExtractAll(DirectoryInfo outDir, bool extract = true, bool uncook = false, EUncookExtension uncookext = EUncookExtension.tga) { var _maincontroller = ServiceLocator.Default.ResolveType <IMainController>(); using var pb = new ProgressBar(); using var p1 = pb.Progress.Fork(); int progress = 0; using var mmf = MemoryMappedFile.CreateFromFile(Filepath, FileMode.Open, Mmfhash, 0, MemoryMappedFileAccess.Read); Parallel.For(0, FileCount, new ParallelOptions { MaxDegreeOfParallelism = 8 }, i => { var info = Files.Values.ToList()[i]; var(file, buffers) = GetFileData(info.NameHash64, mmf); var hash = info.NameHash64; string name = $"{hash:X2}.bin"; if (_maincontroller.Hashdict.ContainsKey(hash)) { name = _maincontroller.Hashdict[hash]; } var outfile = new FileInfo(Path.Combine(outDir.FullName, $"{name}")); if (outfile.Directory == null) { return; } // write main file if (extract) { Directory.CreateDirectory(outfile.Directory.FullName); File.WriteAllBytes(outfile.FullName, file); } // write buffers for (int j = 0; j < buffers.Count; j++) { if (uncook) { #region textures if (Path.GetExtension(name) != ".xbm") { continue; } if (buffers.Count > 1) { //TODO: Log } // read cr2w using var ms = new MemoryStream(file); using var br = new BinaryReader(ms); var cr2w = new CR2WFile(); var result = cr2w.Read(br); if (result != EFileReadErrorCodes.NoError) { continue; } if (!(cr2w.Chunks.FirstOrDefault()?.data is CBitmapTexture xbm) || !(cr2w.Chunks[1]?.data is rendRenderTextureBlobPC blob)) { continue; } // create dds header var width = blob.Header.SizeInfo.Width.val; var height = blob.Header.SizeInfo.Height.val; var mips = blob.Header.TextureInfo.MipCount.val; var slicecount = blob.Header.TextureInfo.SliceCount.val; var alignment = blob.Header.TextureInfo.DataAlignment.val; Directory.CreateDirectory(outfile.Directory.FullName); using (var stream = new FileStream($"{outfile}.dds", FileMode.Create, FileAccess.Write)) { DDSUtils.GenerateAndWriteHeader(stream, new DDSMetadata(width, height, mips, EFormat.BC7_UNORM, alignment, false, slicecount)); var buffer = buffers[j]; stream.Write(buffer); } // convert to texture if (uncookext != EUncookExtension.dds) { try { var di = new FileInfo(outfile.FullName).Directory; TexconvWrapper.Convert(di.FullName, $"{outfile}.dds", uncookext); } catch (Exception e) { Console.WriteLine(e); } } #endregion }
private int ExtractSingleInner(MemoryMappedFile mmf, ulong hash, DirectoryInfo outDir, bool extract = true, bool uncook = false, EUncookExtension uncookext = EUncookExtension.tga) { var maincontroller = ServiceLocator.Default.ResolveType <IMainController>(); var logger = ServiceLocator.Default.ResolveType <ILoggerService>(); var success = false; var(file, buffers) = GetFileData(hash, mmf); string name = $"{hash:X2}.bin"; if (maincontroller.Hashdict.ContainsKey(hash)) { name = maincontroller.Hashdict[hash]; } var outfile = new FileInfo(Path.Combine(outDir.FullName, $"{name}")); if (outfile.Directory == null) { return(0); } // write main file if (extract) { Directory.CreateDirectory(outfile.Directory.FullName); File.WriteAllBytes(outfile.FullName, file); success = true; } // write buffers for (int j = 0; j < buffers.Count; j++) { if (uncook) { #region textures if (Path.GetExtension(name) != ".xbm") { continue; } if (buffers.Count > 1) { //TODO: Log } // read cr2w using var ms = new MemoryStream(file); using var br = new BinaryReader(ms); var cr2w = new CR2WFile(); var result = cr2w.Read(br); if (result != EFileReadErrorCodes.NoError) { continue; } if (!(cr2w.Chunks.FirstOrDefault()?.data is CBitmapTexture xbm) || !(cr2w.Chunks[1]?.data is rendRenderTextureBlobPC blob)) { continue; } // create dds header try { var width = blob.Header.SizeInfo.Width.val; var height = blob.Header.SizeInfo.Height.val; var mips = blob.Header.TextureInfo.MipCount.val; var slicecount = blob.Header.TextureInfo.SliceCount.val; var alignment = blob.Header.TextureInfo.DataAlignment.val; var compression = xbm.Setup.Compression?.WrappedEnum ?? Enums.ETextureCompression.TCM_None; var texformat = CommonFunctions.GetEformatFromCompression(compression); Directory.CreateDirectory(outfile.Directory.FullName); using (var stream = new FileStream($"{outfile}.dds", FileMode.Create, FileAccess.Write)) { DDSUtils.GenerateAndWriteHeader(stream, new DDSMetadata(width, height, mips, texformat, alignment, false, slicecount, false)); var buffer = buffers[j]; stream.Write(buffer); } // success success = true; } catch { success = false; continue; } // convert to texture if (uncookext != EUncookExtension.dds) { try { var di = new FileInfo(outfile.FullName).Directory; TexconvWrapper.Convert(di.FullName, $"{outfile}.dds", uncookext); } catch (Exception e) { // silent } } #endregion } else if (extract) { var buffer = buffers[j]; var bufferpath = $"{outfile}.{j}.buffer"; Directory.CreateDirectory(outfile.Directory.FullName); File.WriteAllBytes(bufferpath, buffer); } } return(success ? 1 : 0); }
private int UncookSingleInner(MemoryMappedFile mmf, ulong hash, DirectoryInfo outDir, EUncookExtension uncookext = EUncookExtension.tga) { var uncooksuccess = false; var(file, buffers) = GetFileData(hash, mmf); if (!Files.ContainsKey(hash)) { return(-1); } string name = Files[hash].NameStr; // checks var outfile = new FileInfo(Path.Combine(outDir.FullName, $"{name}")); if (outfile.Directory == null) { return(-1); } if (buffers.Count > 1) { return(-1); //TODO: can that happen? } var cr2w = new CR2WFile(); using var ms = new MemoryStream(file); using var br = new BinaryReader(ms); cr2w.ReadImportsAndBuffers(br); if (cr2w.StringDictionary[1] != "CBitmapTexture") { return(-1); } br.BaseStream.Seek(0, SeekOrigin.Begin); var result = cr2w.Read(br); if (result != EFileReadErrorCodes.NoError) { return(-1); } if (!(cr2w.Chunks.FirstOrDefault()?.data is CBitmapTexture xbm) || !(cr2w.Chunks[1]?.data is rendRenderTextureBlobPC blob)) { return(-1); } // write buffers foreach (var b in buffers) { #region textures // create dds header var newpath = Path.ChangeExtension(outfile.FullName, "dds"); try { var width = blob.Header.SizeInfo.Width.val; var height = blob.Header.SizeInfo.Height.val; var mips = blob.Header.TextureInfo.MipCount.val; var slicecount = blob.Header.TextureInfo.SliceCount.val; var alignment = blob.Header.TextureInfo.DataAlignment.val; Enums.ETextureRawFormat rawfmt = Enums.ETextureRawFormat.TRF_Invalid; if (xbm.Setup.RawFormat?.WrappedEnum != null) { rawfmt = xbm.Setup.RawFormat.WrappedEnum; } else { } Enums.ETextureCompression compression = Enums.ETextureCompression.TCM_None; if (xbm.Setup.Compression?.WrappedEnum != null) { compression = xbm.Setup.Compression.WrappedEnum; } else { } var texformat = CommonFunctions.GetDXGIFormatFromXBM(compression, rawfmt); Directory.CreateDirectory(outfile.Directory.FullName); using (var stream = new FileStream($"{newpath}", FileMode.Create, FileAccess.Write)) { DDSUtils.GenerateAndWriteHeader(stream, new DDSMetadata(width, height, mips, texformat, alignment, false, slicecount, true)); var buffer = b; stream.Write(buffer); } // success uncooksuccess = true; } catch { uncooksuccess = false; continue; } // convert to texture if (uncookext != EUncookExtension.dds) { try { var di = new FileInfo(outfile.FullName).Directory; TexconvWrapper.Convert(di.FullName, $"{newpath}", uncookext); } catch (Exception e) { // silent } } #endregion } return(uncooksuccess ? 1 : 0); }
public static bool Uncook(CR2WFile cr2w, List <byte[]> buffers, FileInfo outfile, EUncookExtension uncookext) { //We need 2 buffers one for atlas one for tile data if (buffers.Count < 2) { return(false); } if (!(cr2w.Chunks.FirstOrDefault()?.data is Multilayer_Mask mlmask) || !(cr2w.Chunks[1]?.data is rendRenderMultilayerMaskBlobPC blob)) { return(false); } string filename = Path.GetFileNameWithoutExtension(outfile.FullName); string path = outfile.Directory.FullName; uint atlasWidth = blob.Header.AtlasWidth.val; uint atlasHeight = blob.Header.AtlasHeight.val; uint maskWidth = blob.Header.MaskWidth.val; uint maskHeight = blob.Header.MaskHeight.val; uint maskWidthLow = blob.Header.MaskWidthLow.val; uint maskHeightLow = blob.Header.MaskHeightLow.val; uint maskTileSize = blob.Header.MaskTileSize.val; uint maskCount = blob.Header.NumLayers.val; byte[] atlas = buffers[0]; uint[] tiles; //Read tilesdata buffer into appropriate variable type var b = buffers[1]; tiles = new uint[b.Length / 4]; for (int i = 0, j = 0; i < b.Length; i += 4, j++) { tiles[j] = BitConverter.ToUInt32(b, i); } byte[] atlasRaw = new byte[atlasWidth * atlasHeight]; //Decode compressed data into single channel uncompressed //Mlmask always BC4? if (!BlockCompression.DecodeBC(atlas, ref atlasRaw, atlasWidth, atlasHeight, BlockCompression.BlockCompressionType.BC4)) { return(false); } //{ // var mFilename = filename + $"__.dds"; // var newpath = Path.Combine(path, mFilename); // using (var ddsStream = new FileStream($"{newpath}", FileMode.Create, FileAccess.Write)) // { // DDSUtils.GenerateAndWriteHeader(ddsStream, new DDSMetadata(atlasWidth, atlasHeight, 0, EFormat.R8_UNORM, 8, false, 0, false)); // // ddsStream.Write(atlasRaw); // } //} byte[] maskData = new byte[maskWidth * maskHeight]; Directory.CreateDirectory(path); for (int i = 0; i < maskCount; i++) { var mFilename = filename + $"_{i}.dds"; var newpath = Path.Combine(path, mFilename); //Clear instead of allocate new is faster? //Mandatory cause decode does not always write to every pixel Array.Clear(maskData, 0, maskData.Length); Decode(ref maskData, maskWidth, maskHeight, maskWidthLow, maskHeightLow, atlasRaw, atlasWidth, atlasHeight, tiles, maskTileSize, i); using (var ddsStream = new FileStream($"{newpath}", FileMode.Create, FileAccess.Write)) { DDSUtils.GenerateAndWriteHeader(ddsStream, new DDSMetadata(maskWidth, maskHeight, 0, EFormat.R8_UNORM, 8, false, 0, false)); ddsStream.Write(maskData); } //convert texture if neccessary if (uncookext != EUncookExtension.dds && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var di = new FileInfo(outfile.FullName).Directory; TexconvWrapper.Convert(di.FullName, $"{newpath}", uncookext); } } return(true); }
public static bool Uncook(Stream cr2wStream, CR2WFile cr2w, EUncookExtension uncookext) { //We need 2 buffers one for atlas one for tile data if (!(cr2w.Chunks.FirstOrDefault()?.data is Multilayer_Mask mlmask) || !(cr2w.Chunks[1]?.data is rendRenderMultilayerMaskBlobPC blob)) { return(false); } var outfile = new FileInfo(cr2w.FileName); if (outfile.Directory == null) { return(false); } Directory.CreateDirectory(outfile.Directory.FullName); string filename = Path.GetFileNameWithoutExtension(outfile.FullName); string path = outfile.Directory.FullName; uint atlasWidth = blob.Header.AtlasWidth.Value; uint atlasHeight = blob.Header.AtlasHeight.Value; uint maskWidth = blob.Header.MaskWidth.Value; uint maskHeight = blob.Header.MaskHeight.Value; uint maskWidthLow = blob.Header.MaskWidthLow.Value; uint maskHeightLow = blob.Header.MaskHeightLow.Value; uint maskTileSize = blob.Header.MaskTileSize.Value; uint maskCount = blob.Header.NumLayers.Value; byte[] atlas; var atlasRaw = new byte[atlasWidth * atlasHeight]; var atlasBuffer = cr2w.Buffers[0]; cr2wStream.Seek(atlasBuffer.Offset, SeekOrigin.Begin); using (var ms = new MemoryStream()) { cr2wStream.DecompressAndCopySegment(ms, atlasBuffer.DiskSize, atlasBuffer.MemSize); atlas = ms.ToArray(); } //Decode compressed data into single channel uncompressed //Mlmask always BC4? if (!BlockCompression.DecodeBC(atlas, ref atlasRaw, atlasWidth, atlasHeight, BlockCompression.BlockCompressionType.BC4)) { return(false); } //{ // var mFilename = filename + $"__.dds"; // var newpath = Path.Combine(path, mFilename); // using (var ddsStream = new FileStream($"{newpath}", FileMode.Create, FileAccess.Write)) // { // DDSUtils.GenerateAndWriteHeader(ddsStream, new DDSMetadata(atlasWidth, atlasHeight, 0, EFormat.R8_UNORM, 8, false, 0, false)); // // ddsStream.Write(atlasRaw); // } //} //Read tilesdata buffer into appropriate variable type var tileBuffer = cr2w.Buffers[0]; var tiles = new uint[tileBuffer.MemSize / 4]; cr2wStream.Seek(tileBuffer.Offset, SeekOrigin.Begin); using (var ms = new MemoryStream()) using (var br = new BinaryReader(ms)) { cr2wStream.DecompressAndCopySegment(ms, tileBuffer.DiskSize, tileBuffer.MemSize); ms.Seek(0, SeekOrigin.Begin); for (var i = 0; i < tiles.Length; i++) { tiles[i] = br.ReadUInt32(); } } byte[] maskData = new byte[maskWidth * maskHeight]; Directory.CreateDirectory(path); for (int i = 0; i < maskCount; i++) { var mFilename = filename + $"_{i}.dds"; var newpath = Path.Combine(path, mFilename); //Clear instead of allocate new is faster? //Mandatory cause decode does not always write to every pixel Array.Clear(maskData, 0, maskData.Length); Decode(ref maskData, maskWidth, maskHeight, maskWidthLow, maskHeightLow, atlasRaw, atlasWidth, atlasHeight, tiles, maskTileSize, i); using (var ddsStream = new FileStream($"{newpath}", FileMode.Create, FileAccess.Write)) { DDSUtils.GenerateAndWriteHeader(ddsStream, new DDSMetadata(maskWidth, maskHeight, 0, EFormat.R8_UNORM, 8, false, 0, false)); ddsStream.Write(maskData); } //convert texture if neccessary if (uncookext != EUncookExtension.dds && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var di = new FileInfo(outfile.FullName).Directory; TexconvWrapper.Convert(di.FullName, $"{newpath}", uncookext); } } return(true); }