/// <summary> /// Loads the buffer into the pointed location. /// </summary> /// <param name="pDestination">A pointer to the destination of the data.</param> public unsafe void CopyTo(byte *pDestination) { if (_isDeflated) { if (_weakInflatedBufferRef.TryGetTarget(out var buffer)) { fixed(byte *pBuffer = buffer) { Stdlib.MemCpy(pDestination, pBuffer, (UIntPtr)_actualSize); } } else { // Decompress the buffer of the ClipboardItem into the destination. BlockCompression.Inflate(_buffer, _actualSize, pDestination); } } else { fixed(byte *pBuffer = _buffer) { Stdlib.MemCpy(pDestination, pBuffer, (UIntPtr)_actualSize); } } }
public void DoWrite(IProgress <string> progress = null) { var origStream = Stream; SetStream(new MemoryStream()); Write(progress); progress?.Report("Post processing: Compressing file..."); Stream.Position = 0; //Stream.CopyTo(origStream); MemoryStream ms = (MemoryStream)this.Stream; if (_compress) { BlockCompression.WriteBlockFile(origStream, ms.ToArray()); } else { ms.CopyTo(origStream); } this.Stream = origStream; //File.WriteAllBytes("GlobalC_gen.bin", ms.ToArray()); //BlockCompression.WriteBlockFile(origStream, ms.ToArray()); }
public void TestDecompressionToArray() { using FileStream compressedFileStream = new FileStream(@"data\\GlobalC.lzc", FileMode.Open); byte[] decompressedBytes = BlockCompression.ReadBlockFile(compressedFileStream); Assert.AreEqual(9963360, decompressedBytes.Length); }
public void TestDecompressionToStream() { using FileStream compressedFileStream = new FileStream(@"data\\GlobalC.lzc", FileMode.Open); Stream decompressedStream = BlockCompression.StreamBlockFile(compressedFileStream); Assert.AreEqual(9963360, decompressedStream.Length); Assert.AreEqual(0, decompressedStream.Position); }
public static void SetUpTests(TestContext testContext) { using FileStream compressedFileStream = new FileStream(@"data\\GlobalC.lzc", FileMode.Open); Stream decompressedStream = BlockCompression.StreamBlockFile(compressedFileStream); DatabaseChunkBundle chunkBundle = new DatabaseChunkBundle(decompressedStream); chunkBundle.Load(); _database = chunkBundle.Database; }
public void TestCompression() { MemoryStream ms = new MemoryStream(); byte[] data = { 0x1, 0x2, 0x3, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x6, 0x5, 0x5, 0x6, 0x5, 0x5, 0x7, 0x1, 0x2, 0x3, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x6, 0x5, 0x5, 0x6, 0x5, 0x5, 0x7, 0x1, 0x2, 0x3, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x6, 0x5, 0x5, 0x6, 0x5, 0x5, 0x7, 0x1, 0x2, 0x3, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x6, 0x5, 0x5, 0x6, 0x5, 0x5, 0x7, }; BlockCompression.WriteCompressedBlocks(ms, data); }
public static ClipboardItem FromBuffer(DataFormat formatId, byte[] buffer, bool cloneBuffer = true, bool optimizeLongTerm = true) { if (optimizeLongTerm && buffer.Length >= 5 * 1024 * 1024) // 5MiBVV { byte[] deflatedBuffer = BlockCompression.Deflate(buffer); float deflationRatio = (float)buffer.Length / deflatedBuffer.Length; if (deflationRatio > 1.5f) { return(new ClipboardItem(formatId, deflatedBuffer, buffer.Length, isDeflated: true)); } } return(new ClipboardItem(formatId, cloneBuffer ? (byte[])buffer.Clone() : buffer, buffer.Length, isDeflated: false)); }
public static unsafe ClipboardItem FromPointer(DataFormat formatId, byte *bufferPtr, int size) { if (size > 4096) { byte[] deflatedBuffer = BlockCompression.Deflate(bufferPtr, size); float deflationRatio = (float)size / deflatedBuffer.Length; if (deflationRatio > 1.5f) { return(new ClipboardItem(formatId, deflatedBuffer, size, isDeflated: true)); } } byte[] newBuffer = new byte[size]; fixed(byte *dest = newBuffer) { Stdlib.MemCpy(dest, bufferPtr, (UIntPtr)size); } return(new ClipboardItem(formatId, newBuffer, newBuffer.Length, isDeflated: false)); }
/// <summary> /// Loads the data as a byte array. /// </summary> /// <returns>The byte array representation of the data.</returns> public byte[] GetDataBuffer() { if (_buffer == null) { throw new InvalidOperationException(); } if (_isDeflated) { if (!_weakInflatedBufferRef.TryGetTarget(out byte[] inflatedBuffer)) { inflatedBuffer = new byte[_actualSize]; BlockCompression.Inflate(_buffer, _actualSize, inflatedBuffer); _weakInflatedBufferRef.SetTarget(inflatedBuffer); } return(inflatedBuffer); } else { return(_buffer); } }
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); }
protected override void PrepareStream() { SetStream(new MemoryStream(BlockCompression.ReadBlockFile(Stream))); }
public static bool ConvertMultilayerMaskToDdsStreams(Multilayer_Mask mask, out List <Stream> streams) { streams = new List <Stream>(); if (mask.RenderResourceBlob.RenderResourceBlobPC.GetValue() is not rendRenderMultilayerMaskBlobPC blob) { return(false); } uint atlasWidth = blob.Header.AtlasWidth; uint atlasHeight = blob.Header.AtlasHeight; uint maskWidth = blob.Header.MaskWidth; uint maskHeight = blob.Header.MaskHeight; uint maskWidthLow = blob.Header.MaskWidthLow; uint maskHeightLow = blob.Header.MaskHeightLow; uint maskTileSize = blob.Header.MaskTileSize; uint maskCount = blob.Header.NumLayers; var atlasRaw = new byte[atlasWidth * atlasHeight]; //Decode compressed data into single channel uncompressed //Mlmask always BC4? if (!BlockCompression.DecodeBC(blob.AtlasData.Buffer.GetBytes(), ref atlasRaw, atlasWidth, atlasHeight, BlockCompression.BlockCompressionType.BC4)) { return(false); } //atlasRaw = blob.AtlasData.Buffer.GetBytes(); //Read tilesdata buffer into appropriate variable type var tileBuffer = blob.TilesData.Buffer; var tiles = new uint[tileBuffer.MemSize / 4]; using (var ms = new MemoryStream(tileBuffer.GetBytes())) using (var br = new BinaryReader(ms)) { ms.Seek(0, SeekOrigin.Begin); for (var i = 0; i < tiles.Length; i++) { tiles[i] = br.ReadUInt32(); } } var maskData = new byte[maskWidth * maskHeight]; for (var i = 0; i < maskCount; i++) { //Clear instead of allocate new is faster? //Mandatory cause decode does not always write to every pixel Array.Clear(maskData, 0, maskData.Length); try { Decode(ref maskData, maskWidth, maskHeight, maskWidthLow, maskHeightLow, atlasRaw, atlasWidth, atlasHeight, tiles, maskTileSize, i); } catch { throw; } if (WolvenTesting.IsTesting) { continue; } var ms = new MemoryStream(); DDSUtils.GenerateAndWriteHeader(ms, new DDSMetadata(maskWidth, maskHeight, 1, 1, 0, 0, 0, DXGI_FORMAT.DXGI_FORMAT_R8_UNORM, TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D, 8, true)); ms.Write(maskData); ms.Seek(0, SeekOrigin.Begin); //var stream = new MemoryStream(DDSUtils.ConvertToDdsMemory(ms, EUncookExtension.tga, DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM, false, false)); ms = new MemoryStream( Texconv.ConvertToDds( new MemoryStream(Texconv.ConvertFromDds(ms, EUncookExtension.tga)), EUncookExtension.tga, DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM)); streams.Add(ms); } return(true); }
public bool UncookMlmask(Stream cr2wStream, FileInfo outfile, MlmaskExportArgs args) { // read the cr2wfile var cr2w = _wolvenkitFileService.ReadRed4File(cr2wStream); if (cr2w == null || cr2w.RootChunk is not Multilayer_Mask mlmask || mlmask.RenderResourceBlob.RenderResourceBlobPC.Chunk is not rendRenderMultilayerMaskBlobPC blob) { return(false); } uint atlasWidth = blob.Header.AtlasWidth; uint atlasHeight = blob.Header.AtlasHeight; uint maskWidth = blob.Header.MaskWidth; uint maskHeight = blob.Header.MaskHeight; uint maskWidthLow = blob.Header.MaskWidthLow; uint maskHeightLow = blob.Header.MaskHeightLow; uint maskTileSize = blob.Header.MaskTileSize; uint maskCount = blob.Header.NumLayers; var atlasRaw = new byte[atlasWidth * atlasHeight]; //Decode compressed data into single channel uncompressed //Mlmask always BC4? if (!BlockCompression.DecodeBC(blob.AtlasData.Buffer.GetBytes(), 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 = blob.TilesData.Buffer; var tiles = new uint[tileBuffer.MemSize / 4]; using (var ms = new MemoryStream(tileBuffer.GetBytes())) using (var br = new BinaryReader(ms)) { ms.Seek(0, SeekOrigin.Begin); for (var i = 0; i < tiles.Length; i++) { tiles[i] = br.ReadUInt32(); } } // write texture to file var subdir = new DirectoryInfo(Path.GetFullPath(outfile.FullName)); if (!subdir.Exists) { Directory.CreateDirectory(subdir.FullName); } var maskData = new byte[maskWidth * maskHeight]; var masks = new List <string>(); for (var i = 0; i < maskCount; i++) { //Clear instead of allocate new is faster? //Mandatory cause decode does not always write to every pixel Array.Clear(maskData, 0, maskData.Length); try { Decode(ref maskData, maskWidth, maskHeight, maskWidthLow, maskHeightLow, atlasRaw, atlasWidth, atlasHeight, tiles, maskTileSize, i); } catch { return(false); } if (WolvenTesting.IsTesting) { continue; } // create dds stream using var ms = new MemoryStream(); DDSUtils.GenerateAndWriteHeader(ms, new DDSMetadata( maskWidth, maskHeight, 1, 1, 0, 0, 0, DXGI_FORMAT.DXGI_FORMAT_R8_UNORM, TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D, 8, true)); ms.Write(maskData); var newpath = Path.Combine(subdir.FullName, $"{i}.dds"); if (args.UncookExtension == EMlmaskUncookExtension.dds) { using var ddsStream = new FileStream($"{newpath}", FileMode.Create, FileAccess.Write); ms.Seek(0, SeekOrigin.Begin); ms.CopyTo(ddsStream); masks.Add($"{subdir.Name}/{i}.dds"); } //else if (args.UncookExtension == EUncookExtension.tga) //{ // using (var ddsStream = new FileStream($"{newpath}.tga", FileMode.Create, FileAccess.Write)) // { // ms.Seek(0, SeekOrigin.Begin); // using (var ms2 = new MemoryStream(DDSUtils.ConvertFromDdsMemory(ms, EUncookExtension.tga))) // { // var br = new BinaryReader(ms2); // br.BaseStream.Seek(14, SeekOrigin.Begin); // ushort height = br.ReadUInt16(); // br.BaseStream.Seek(17, SeekOrigin.Begin); // byte descriptor = br.ReadByte(); // var bw = new BinaryWriter(ms2); // bw.BaseStream.Seek(10, SeekOrigin.Begin); // bw.Write(height); // bw.BaseStream.Seek(17, SeekOrigin.Begin); // bw.Write(descriptor ^ 0b00001000); // bw.Flush(); // ms2.Position = 0; // ms2.CopyTo(ddsStream); // } // } //} else { // convert ms.Seek(0, SeekOrigin.Begin); if (!Texconv.ConvertFromDdsAndSave(ms, newpath, args)) { return(false); } { masks.Add($"{subdir.Name}/{i}.png"); } } } // write metadata var masklist = Path.ChangeExtension(outfile.FullName, "masklist"); File.WriteAllLines(masklist, masks.ToArray()); return(true); }
public bool UncookMlmask(Stream cr2wStream, FileInfo outfile, MlmaskExportArgs args) { // read the cr2wfile var cr2w = _wolvenkitFileService.TryReadCr2WFile(cr2wStream); if (cr2w == null) { return(false); } //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); } 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[1]; 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]; for (int i = 0; i < maskCount; i++) { var mFilename = Path.GetFileNameWithoutExtension(outfile.FullName) + $"_{i}.dds"; //var mFilename = Path.GetFileName(outfile.FullName) + $".{i}.dds"; // TODO:we should use this at some point var newpath = Path.Combine(outfile.Directory.FullName, mFilename); //Clear instead of allocate new is faster? //Mandatory cause decode does not always write to every pixel Array.Clear(maskData, 0, maskData.Length); try { Decode(ref maskData, maskWidth, maskHeight, maskWidthLow, maskHeightLow, atlasRaw, atlasWidth, atlasHeight, tiles, maskTileSize, i); } catch { return(false); } if (WolvenTesting.IsTesting) { continue; } // write texture to file using (var ms = new MemoryStream()) { // create dds stream DDSUtils.GenerateAndWriteHeader(ms, new DDSMetadata( maskWidth, maskHeight, 1, 1, 0, 0, 0, DXGI_FORMAT.DXGI_FORMAT_R8_UNORM, TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D, 8, true)); ms.Write(maskData); if (args.UncookExtension == EUncookExtension.dds) { using (var ddsStream = new FileStream($"{newpath}", FileMode.Create, FileAccess.Write)) { ms.Seek(0, SeekOrigin.Begin); ms.CopyTo(ddsStream); } } else { // convert ms.Seek(0, SeekOrigin.Begin); if (!DDSUtils.ConvertFromDdsAndSave(ms, newpath, args)) { return(false); } } } } return(true); }