Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }