Ejemplo n.º 1
0
        //public static DdsImage Xbm2Dds(CBitmapTexture xbm, byte[] rawimage)
        //{
        //    if (xbm == null || rawimage == null)
        //        return null;
        //    return new DdsImage(Xbm2DdsBytes(xbm, rawimage));
        //}



        public static byte[] Xbm2DdsBytes(CBitmapTexture xbm)
        {
            if (xbm == null)
            {
                return(null);
            }

            int residentMipIndex = xbm.GetVariableByName("ResidentMipIndex") == null ? 0 : (int)((CUInt8)xbm.GetVariableByName("ResidentMipIndex")).val;

            byte[] bytesource;
            // handle cooked xbms
            if (xbm.GetVariableByName("SourceData") == null)
            {
                bytesource = xbm.Residentmip.Bytes;
            }
            // handle imported xbms
            else
            {
                bytesource = xbm.Mips.elements[residentMipIndex].Bytes;
            }

            using (var ms = new MemoryStream())
                using (var bw = new BinaryWriter(ms))
                {
                    DDSUtils.GenerateAndWriteHeader(bw.BaseStream, Xbm2Ddsheader(xbm));

                    bw.Write(bytesource);

                    ms.Flush();

                    return(ms.ToArray());
                }
        }
Ejemplo n.º 2
0
        public void TestThreeSingle()
        {
            byte[] concat_aab = DDSUtils.ConcatByteArrays(a, a, b);

            for (int k = 0; k < aab.Length; k++)
            {
                Assert.AreEqual(aab[k], concat_aab[k]);
            }
        }
Ejemplo n.º 3
0
        private byte[] calculateRampRateWord(double RampRate)
        {
            // Calculate the the 8bit word. since it is assumed
            // to be nonzero a 0 is a one (and a 255 a 256)
            // that's why we substract one from the result. Cheers
            int word = (int)(Math.Round(RampRate * rampStep)) - 1;

            // Int has 4 bytes, but Ramp Rate word only 1
            return(DDSUtils.IntToMSByteArray(word, 1).ToArray());
        }
Ejemplo n.º 4
0
        static List <MemoryStream> ContainTextureStreams(CR2WFile cr2w, MemoryStream texbuffer)
        {
            List <MemoryStream> textureStreams = new List <MemoryStream>();

            int Index = int.MaxValue;

            for (int i = 0; i < cr2w.Chunks.Count; i++)
            {
                if (cr2w.Chunks[i].REDType == "rendRenderMorphTargetMeshBlob")
                {
                    Index = i;
                }
            }
            int           Count    = (cr2w.Chunks[Index].Data as rendRenderMorphTargetMeshBlob).Header.TargetTextureDiffsData.Count;
            int           texCount = 0;
            List <UInt32> TargetDiffsDataOffset     = new List <UInt32>();
            List <UInt32> TargetDiffsDataSize       = new List <UInt32>();
            List <UInt32> TargetDiffsMipLevelCounts = new List <UInt32>();
            List <UInt32> TargetDiffsWidth          = new List <UInt32>();

            for (int i = 0; i < Count; i++)
            {
                if ((cr2w.Chunks[Index].Data as rendRenderMorphTargetMeshBlob).Header.TargetTextureDiffsData[i].TargetDiffsDataSize.Count == 0)
                {
                    break;
                }
                TargetDiffsDataOffset.Add((cr2w.Chunks[Index].Data as rendRenderMorphTargetMeshBlob).Header.TargetTextureDiffsData[i].TargetDiffsDataOffset[0].Value);
                TargetDiffsDataSize.Add((cr2w.Chunks[Index].Data as rendRenderMorphTargetMeshBlob).Header.TargetTextureDiffsData[i].TargetDiffsDataSize[0].Value);
                TargetDiffsMipLevelCounts.Add((cr2w.Chunks[Index].Data as rendRenderMorphTargetMeshBlob).Header.TargetTextureDiffsData[i].TargetDiffsMipLevelCounts[0].Value);
                TargetDiffsWidth.Add((cr2w.Chunks[Index].Data as rendRenderMorphTargetMeshBlob).Header.TargetTextureDiffsData[i].TargetDiffsWidth[0].Value);
                texCount++;
            }

            BinaryReader texbr = new BinaryReader(texbuffer);

            for (int i = 0; i < texCount; i++)
            {
                texbuffer.Position = TargetDiffsDataOffset[i];
                byte[] bytes = texbr.ReadBytes((int)TargetDiffsDataSize[i]);

                MemoryStream ms       = new MemoryStream();
                DDSMetadata  metadata = new DDSMetadata(TargetDiffsWidth[i], TargetDiffsWidth[i], TargetDiffsMipLevelCounts[i], EFormat.BC7_UNORM, 16, false, 0, true);
                DDSUtils.GenerateAndWriteHeader(ms, metadata);
                BinaryWriter bw = new BinaryWriter(ms);
                bw.Write(bytes);
                textureStreams.Add(ms);
            }

            return(textureStreams);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Create a byte array from a Redengine CBitmapTexture with Wkit DDS Utility
        /// </summary>
        /// <param name="xbm"></param>
        /// <returns></returns>
        public static byte[] Xbm2DdsBytes(CBitmapTexture xbm)
        {
            if (xbm == null)
            {
                return(null);
            }

            using var ms = new MemoryStream();
            using var bw = new BinaryWriter(ms);
            DDSUtils.GenerateAndWriteHeader(bw.BaseStream, GetDDSMetadata(xbm));

            bw.Write(xbm.GetBytes());

            ms.Flush();

            return(ms.ToArray());
        }
Ejemplo n.º 6
0
        private static List <MemoryStream> ContainTextureStreams(rendRenderMorphTargetMeshBlob blob, MemoryStream texbuffer)
        {
            var textureStreams = new List <MemoryStream>();

            var Count    = blob.Header.TargetTextureDiffsData.Count;
            var texCount = 0;
            var TargetDiffsDataOffset     = new List <uint>();
            var TargetDiffsDataSize       = new List <uint>();
            var TargetDiffsMipLevelCounts = new List <uint>();
            var TargetDiffsWidth          = new List <uint>();

            for (var i = 0; i < Count; i++)
            {
                if (blob.Header.TargetTextureDiffsData[i].TargetDiffsDataSize.Count == 0)
                {
                    break;
                }

                TargetDiffsDataOffset.Add(blob.Header.TargetTextureDiffsData[i].TargetDiffsDataOffset[0]);
                TargetDiffsDataSize.Add(blob.Header.TargetTextureDiffsData[i].TargetDiffsDataSize[0]);
                TargetDiffsMipLevelCounts.Add(blob.Header.TargetTextureDiffsData[i].TargetDiffsMipLevelCounts[0]);
                TargetDiffsWidth.Add(blob.Header.TargetTextureDiffsData[i].TargetDiffsWidth[0]);
                texCount++;
            }

            var texbr = new BinaryReader(texbuffer);

            for (var i = 0; i < texCount; i++)
            {
                texbuffer.Position = TargetDiffsDataOffset[i];
                var bytes = texbr.ReadBytes((int)TargetDiffsDataSize[i]);

                var ms       = new MemoryStream();
                var metadata = new DDSMetadata(
                    TargetDiffsWidth[i], TargetDiffsWidth[i],
                    1, 1, TargetDiffsMipLevelCounts[i], 0, 0, DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM, TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D, 16, true);
                DDSUtils.GenerateAndWriteHeader(ms, metadata);
                var bw = new BinaryWriter(ms);
                bw.Write(bytes);
                textureStreams.Add(ms);
            }

            return(textureStreams);
        }
Ejemplo n.º 7
0
        public static byte[] Xbm2DdsBytes(CBitmapTexture xbm, byte[] bytesource)
        {
            if (xbm == null)
            {
                return(null);
            }

            using (var ms = new MemoryStream())
                using (var bw = new BinaryWriter(ms))
                {
                    DDSUtils.GenerateAndWriteHeader(bw.BaseStream, Xbm2Ddsheader(xbm));

                    bw.Write(bytesource);

                    ms.Flush();

                    return(ms.ToArray());
                }
        }
Ejemplo n.º 8
0
        public Message PhaseAsChannelWord(double Phase)
        {
            // The Channel Word Register are 4byte long and the PhaseOffsetWord only 14bit long
            // the PhaseOffsetWord has to be MSB aligned in the register
            int PhaseOffsetWord = calculatePhaseOffsetWord(Phase);

            // First shift the word by two bits to the left to make it MSB aligned
            // for a two byte register
            PhaseOffsetWord = PhaseOffsetWord << 2;

            // Then convert it to MSBytearray
            Message msg = DDSUtils.IntToMSByteArray(PhaseOffsetWord, 2);

            // Finally make sure that the two last bits are zero by doing a
            // bitwise and with 1111 1100 = 0xFC
            msg[1] = (byte)(msg[1] & 0xFC);

            // Add to zero bytes for the remaining byte registers
            msg.AddRange(new byte[] { 0x00, 0x00 });

            return(msg);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Send message to EP1. This routine will append a checksum byte at the end of the message. So
        /// don't include it in the message passed to this routine
        /// </summary>
        /// <param name="message">Message to be sent without checksum byte</param>
        private void sendToEP1(Message message)
        {
            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Recieved message to send to EP1: {0}", message.ToString());
            }

            byte checksum = DDSUtils.Checksum(message);

            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Appending checksum byte 0x{0} to message", checksum);
            }

            message.Add(checksum);

            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Sending message to EP1: {0}", message.ToString());
            }
            device.SendDataToEP1(message.ToArray());
        }
Ejemplo n.º 10
0
        public static DdsImage Xbm2Dds(CR2WExportWrapper imagechunk)
        {
            try
            {
                var image            = ((CBitmapTexture)(imagechunk.data)).Image;
                var compression      = imagechunk.GetVariableByName("compression").ToString();
                var width            = uint.Parse(imagechunk.GetVariableByName("width").ToString());
                var height           = uint.Parse(imagechunk.GetVariableByName("height").ToString());
                var unk2             = uint.Parse(imagechunk.GetVariableByName("unk2").ToString());
                var residentMipIndex = imagechunk.GetVariableByName("residentMipIndex") != null?uint.Parse(imagechunk.GetVariableByName("residentMipIndex").ToString()) : 0;

                var mips     = (CBufferUInt32 <CVector3 <CUInt32> >)imagechunk.GetVariableByName("mips");
                var tempfile = new MemoryStream();

                var format = ETextureFormat.TEXFMT_R8G8B8A8;
                switch (compression)
                {
                case "TCM_DXTNoAlpha":
                    format = ETextureFormat.TEXFMT_BC1;
                    break;

                case "TCM_DXTAlpha":
                    format = ETextureFormat.TEXFMT_BC3;
                    break;

                case "TCM_NormalsHigh":
                    format = ETextureFormat.TEXFMT_BC3;
                    break;

                case "TCM_Normals":
                    format = ETextureFormat.TEXFMT_BC1;
                    break;

                case "TCM_NormalsGloss":
                    format = ETextureFormat.TEXFMT_BC3;
                    break;

                case "TCM_QualityControl":
                    format = ETextureFormat.TEXFMT_BC3;
                    break;

                default:
                    throw new Exception("Invalid compression type! [" + compression + "]");
                }


                using (var bw = new BinaryWriter(tempfile))
                {
                    var residentmipwidth  = mips.elements[(int)residentMipIndex].x.val;
                    var residentmipheight = mips.elements[(int)residentMipIndex].y.val;
                    var residentmipcount  = mips.elements.Count - residentMipIndex;

                    var metadata = new DDSMetadata(residentmipwidth, residentmipheight, (uint)residentmipcount, format);
                    DDSUtils.GenerateAndWriteHeader(bw.BaseStream, metadata);

                    bw.Write(image.Bytes);
                }
                tempfile.Flush();
#if DEBUG
                //File.WriteAllBytes(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\asd.dds",tempfile.ToArray());
#endif
                return(new DdsImage(tempfile.ToArray()));
            }
            catch (Exception e)
            {
                string            message = e.Message;
                string            caption = "Error!";
                MessageBoxButtons buttons = MessageBoxButtons.OK;
                MessageBox.Show(message, caption, buttons);
                return(null);
            }
        }
Ejemplo n.º 11
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);
        }
Ejemplo n.º 12
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.º 13
0
        private byte[] calculateFrequencyTuningWordAsBytes(double frequency)
        {
            int FTW = calculateFrequencyTuningWord(frequency);

            return(DDSUtils.IntToMSByteArray(FTW).ToArray());
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
        public void Import(FileInfo txtimageList, FileInfo outFile)
        {
            var files = File.ReadAllLines(txtimageList.FullName);

            #region InitandVerify

            mlmask = new MLMaskContainer();
            List <RawTexContainer> textures = new List <RawTexContainer>();
            RawTexContainer        white    = new RawTexContainer();
            white._pixels = new Byte[16];
            Array.Fill <Byte>(white._pixels, 255);
            white._width  = 4;
            white._height = 4;
            textures.Add(white);

            int lineIdx = 1;
            foreach (var f in files)
            {
                if (!File.Exists(f))
                {
                    throw new FileNotFoundException($"Line{{lineIdx}}: \"{f}\" Make sure the file path is valid and exists (paths are specified line by line in ascending layer order in masklist)");
                }

                var ms      = new MemoryStream(File.ReadAllBytes(f));
                var s       = Path.GetExtension(f).ToLower();
                var euncook = Enum.Parse <EUncookExtension>(Path.GetExtension(f).ToLower().Replace(".", ""));
                if (euncook != EUncookExtension.dds)
                {
                    ms = new MemoryStream(DDSUtils.ConvertToDdsMemory(ms, euncook, DXGI_FORMAT.DXGI_FORMAT_R8_UNORM));
                }
                else
                {
                    // why dds to dds?, to make sure format is r8_unorm
                    ms = new MemoryStream(DDSUtils.ConvertToDdsMemory(new MemoryStream(DDSUtils.ConvertFromDdsMemory(ms, EUncookExtension.tga)), EUncookExtension.tga, DXGI_FORMAT.DXGI_FORMAT_R8_UNORM));
                }
                ms.Seek(0, SeekOrigin.Begin);
                DDS_HEADER header;
                DDSUtils.TryReadDdsHeader(ms, out header);
                if (header.dwWidth != header.dwHeight)
                {
                    throw new Exception($"Texture {f}: width={header.dwWidth},height={header.dwHeight} must have an aspect ratio of 1:1");
                }

                // One bitset check
                if ((((header.dwWidth - 1) & header.dwHeight) != 0) || (header.dwWidth == 0))
                {
                    throw new Exception($"Texture {f}: width={header.dwWidth},height={header.dwHeight} must have dimensions in powers of 2");
                }


                //if (header.dwMipMapCount > 1)
                //    throw new Exception($"Texture {f}: Mipmaps={header.dwMipMapCount}, mimap count must be equal to 1");

                //if ((ms.Length - headerLength) != (header.dwWidth * header.dwHeight))
                //    throw new Exception("Not R8_UNORM 8bpp image format or more than 1mipmaps or rowstride is not equal to width or its a dx10 dds(unsupported)");

                var br = new BinaryReader(ms);
                ms.Seek(headerLength, SeekOrigin.Begin);
                Byte[] bytes      = br.ReadBytes((int)(header.dwWidth * header.dwHeight));
                bool   whiteCheck = true;
                for (int i = 0; i < bytes.Length; i++)
                {
                    if (bytes[i] != 255)
                    {
                        whiteCheck = false;
                        break;
                    }
                }
                if (whiteCheck)
                {
                    throw new Exception("No need to provide the 1st/any blank white mask layer, tool will generate 1st blank white layer automatically");
                }

                RawTexContainer tex = new RawTexContainer();
                tex._width  = header.dwWidth;
                tex._height = header.dwHeight;
                tex._pixels = bytes;
                textures.Add(tex);
                lineIdx++;
            }
            mlmask.layers = textures.ToArray();
            #endregion

            Create();
            Write(outFile);
        }
Ejemplo n.º 16
0
        /// <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
                    }
Ejemplo n.º 17
0
        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);
        }
Ejemplo n.º 18
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);
        }
Ejemplo n.º 19
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);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="outpath"></param>
        public void Write(string outpath, ILoggerService logger = null)
        {
            logger?.LogString($"[TextureCache] Writing begun.", Logtype.Important);
            logger?.LogString($"[TextureCache] Found {Files.Count} files.", Logtype.Important);
            int page = 0;

            using (var cacheFileStream = new FileStream(outpath, FileMode.Create, FileAccess.Write))
                using (var cacheWriter = new BinaryWriter(cacheFileStream))
                {
                    // write files

                    #region Write Compressed Files

                    foreach (var ti in Files)
                    {
                        ti.ParentFile = outpath;
                        var ddsfile = ti.FullName;
                        if (!File.Exists(ddsfile))
                        {
                            continue;
                        }

                        // checks
                        long ddssize = -1;
                        // get dds file size //TODO: make this better
                        using (var readfs = new FileStream(ddsfile, FileMode.Open, FileAccess.Read))
                        {
                            ddssize = readfs.Length - 128;
                        }
                        if (ti.IsCube != 0)
                        {
                            if (ddssize % 6 != 0)
                            {
                                throw new CacheWritingException($"{ti.Name} incorrect cubemap (not divisible by 6).");
                            }
                        }
                        ti.UncompressedSize = (uint)ddssize;
                        var ddsoffset   = (uint)128; // dds header size
                        var startoffset = cacheFileStream.Position;

                        // check for alignment
                        if (cacheFileStream.Position % 4096 != 0)
                        {
                            throw new CacheWritingException($"{ti.Name} improperly aligned (pos: {cacheFileStream.Position}).");
                        }

                        // cubemaps
                        if (ti.IsCube != 0)
                        {
                            // dds cube textures are structured in 6 faces (each with mipmaps)
                            // files in the texture cache are structured by mipmaps (each with 6 faces)
                            // sigh...
                            using (var file = MemoryMappedFile.CreateFromFile(ddsfile, FileMode.Open))
                            {
                                #region Main Image

                                // get main image
                                var imgsize = DDSUtils.CalculateMipMapSize(ti.BaseWidth, ti.BaseHeight, ti.Format);
                                ti.PageOffset = (uint)(cacheFileStream.Position / 4096);

                                // all faces and mipmaps get compressed at once
                                using (var allfacesms = new MemoryStream())
                                {
                                    for (int i = 0; i < 6; i++)
                                    {
                                        var faceoffset = 128 + ddssize / 6 * i;
                                        using (var vs = file.CreateViewStream(faceoffset, imgsize,
                                                                              MemoryMappedFileAccess.Read))
                                        {
                                            vs.CopyTo(allfacesms);
                                        }
                                    }

                                    // compress the assembled stream of all faces
                                    ti.Size  = 6 * imgsize;
                                    ti.ZSize = (uint)WriteImgFromStream(allfacesms, cacheWriter, (byte)(ti.NumMipOffsets)).Item1;
                                }

                                #endregion Main Image

                                #region MipMaps

                                // no mipmaps means NumMipOffsets is 0
                                var totalmipmapsizeuptonow = 0;
                                for (int i = 0; i < ti.NumMipOffsets; i++)
                                {
                                    uint mipWidth  = (uint)(ti.BaseWidth / (Math.Pow(2, i + 1)));
                                    uint mipHeight = (uint)(ti.BaseHeight / (Math.Pow(2, i + 1)));
                                    var  mipsize   = DDSUtils.CalculateMipMapSize(mipWidth, mipHeight, ti.Format);
                                    // last 6 mips are concatenated into one compressed buffer
                                    // TODO: non-square textures. fml
                                    if (mipWidth == 32)
                                    {
                                        mipsize = 696;
                                    }
                                    byte idx = (byte)(ti.NumMipOffsets - 1 - i);

                                    // all faces and mipmaps get compressed at once
                                    using (var allmips = new MemoryStream())
                                    {
                                        for (int j = 0; j < 6; j++)
                                        {
                                            // find correct mip: divide dds by 6 + the main size + the size of all mips before the current one

                                            var mipoffset = (ddssize / 6 * j) + (ti.Size / 6) + (totalmipmapsizeuptonow);
                                            using (var vs = file.CreateViewStream(mipoffset, mipsize,
                                                                                  MemoryMappedFileAccess.Read))
                                            {
                                                vs.CopyTo(allmips);
                                            }
                                        }

                                        // compress the assembled stream of all mipmaps
                                        totalmipmapsizeuptonow += (int)mipsize;
                                        mipsize           *= 6; //TODO
                                        var(zsize, offset) = WriteImgFromStream(allmips, cacheWriter, idx);
                                        ti.MipMapInfo.Add(new MipmapInfo(offset, (uint)zsize, (uint)mipsize, idx));
                                        MipOffsets.Add((uint)offset);
                                    }

                                    ti.MipOffsetIndex = MipOffsets.Count;
                                    ddsoffset        += mipsize;
                                }

                                #endregion MipMaps
                            }
                        }
                        else
                        {
                            using (var file = MemoryMappedFile.CreateFromFile(ddsfile, FileMode.Open))
                            {
                                #region Main Image

                                // get main image
                                ti.Size       = DDSUtils.CalculateMipMapSize(ti.BaseWidth, ti.BaseHeight, ti.Format);
                                ti.PageOffset = (uint)(cacheFileStream.Position / 4096);

                                // compress image
                                using (var vs = file.CreateViewStream(ddsoffset, ti.Size, MemoryMappedFileAccess.Read))
                                {
                                    ti.ZSize = (uint)WriteImgFromStream(vs, cacheWriter, (byte)(ti.NumMipOffsets)).Item1;
                                }

                                #endregion Main Image

                                #region MipMaps

                                // no mipmaps means NumMipOffsets is 0
                                for (int i = 0; i < ti.NumMipOffsets; i++)
                                {
                                    uint mipWidth  = (uint)(ti.BaseWidth / (Math.Pow(2, i + 1)));
                                    uint mipHeight = (uint)(ti.BaseHeight / (Math.Pow(2, i + 1)));
                                    var  mipsize   = DDSUtils.CalculateMipMapSize(mipWidth, mipHeight, ti.Format);

                                    // last 6 mips are concatenated into one compressed buffer
                                    // TODO: non-square textures. fml
                                    if (mipWidth == 32)
                                    {
                                        mipsize = 696;
                                    }

                                    byte idx = (byte)(ti.NumMipOffsets - 1 - i);

                                    // compress image and write to cache
                                    using (var viewstream =
                                               file.CreateViewStream(ddsoffset, mipsize, MemoryMappedFileAccess.Read))
                                    {
                                        var(zsize, offset) = WriteImgFromStream(viewstream, cacheWriter, idx);
                                        ti.MipMapInfo.Add(new MipmapInfo(offset, (uint)zsize, (uint)mipsize, idx));
                                        MipOffsets.Add((uint)offset);
                                    }

                                    ti.MipOffsetIndex = MipOffsets.Count;
                                    ddsoffset        += mipsize;
                                }

                                #endregion MipMaps
                            }
                        }

                        //TODO: check if the complete dds file is read

                        // padding to next page (4096 byte pages)
                        var endoffset = cacheFileStream.Position;
                        page = (int)(endoffset / 4096);
                        var paddinglen = (4096 * (page + 1)) - endoffset;
                        var padding    = new byte[paddinglen];
                        cacheWriter.Write(padding);

                        ti.CompressedSize = (uint)(endoffset - startoffset);

                        logger?.LogString($"Written {ti.Name}", Logtype.Normal);
                    }

                    #endregion Write Compressed Files

                    // calculate final stats
                    UsedPages          = (uint)page + 1;
                    EntryCount         = (uint)Files.Count;
                    MipTableEntryCount = (uint)MipOffsets.Count;

                    // write tables

                    #region Tables

                    foreach (var mipOffset in MipOffsets)
                    {
                        cacheWriter.Write(mipOffset);
                    }

                    using (var ms = new MemoryStream())
                        using (var bw = new BinaryWriter(ms))
                        {
                            // mipmaptable
                            var startpos = ms.Position;

                            var endpos = ms.Position;

                            // string table
                            //updates this.StringTableSize and all textureCacheItem.StringTableOffset
                            //startpos = ms.Position;
                            foreach (var textureCacheItem in Files)
                            {
                                var filename = textureCacheItem.Name;
                                bw.WriteCR2WString(filename);
                                textureCacheItem.StringTableOffset = (int)bw.BaseStream.Position;
                            }
                            endpos          = ms.Position;
                            StringTableSize = (uint)(endpos - startpos);

                            // entry table
                            startpos = ms.Position;
                            foreach (var textureCacheItem in Files)
                            {
                                textureCacheItem.Write(bw);
                            }
                            endpos = ms.Position;

                            Crc = CalculateChecksum(ms.ToArray());

                            ms.Seek(0, SeekOrigin.Begin);
                            ms.CopyTo(cacheFileStream);
                        }

                    #endregion Tables

                    // write footer
                    WriteFooter(cacheWriter);

                    logger?.LogString($"[TextureCache] Writing successful.", Logtype.Success);
                }
        }
Ejemplo n.º 21
0
        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);
        }
Ejemplo n.º 22
0
        public void Extract(Stream output)
        {
            using (var file = MemoryMappedFile.CreateFromFile(this.ParentFile, FileMode.Open))
            {
                // generate header
                var metadata = new DDSMetadata(
                    BaseWidth,
                    BaseHeight,
                    (uint)Mipcount,
                    Format,
                    BaseAlignment,
                    IsCube == 1,
                    SliceCount,
                    false
                    );
                DDSUtils.GenerateAndWriteHeader(output, metadata);

                if (IsCube == 0)
                {
                    using (var viewstream = file.CreateViewStream((PageOffset * 4096) + 9, ZSize, MemoryMappedFileAccess.Read))
                    {
                        //if ( format != ETextureFormat.TEXFMT_R8G8B8A8)
                        new ZlibStream(viewstream, CompressionMode.Decompress).CopyTo(output);
                    }
                    for (int i = 0; i < NumMipOffsets; i++)
                    {
                        var mippageoffset = MipMapInfo[i].Offset;
                        var mipzsize      = MipMapInfo[i].ZSize;

                        using (var viewstream = file.CreateViewStream((mippageoffset), mipzsize, MemoryMappedFileAccess.Read))
                        {
                            //if ( format != ETextureFormat.TEXFMT_R8G8B8A8)
                            new ZlibStream(viewstream, CompressionMode.Decompress).CopyTo(output);
                        }
                    }
                }
                else
                {
                    using (var imagestream = new MemoryStream())
                        using (var mipmapstream = new MemoryStream())
                            using (var imagereader = new BinaryReader(imagestream))
                                using (var mipmapreader = new BinaryReader(mipmapstream))
                                {
                                    // extract to memory
                                    // image
                                    using (var vs = file.CreateViewStream((PageOffset * 4096) + 9, ZSize, MemoryMappedFileAccess.Read))
                                    {
                                        // extracts all 6 faces after each other
                                        new ZlibStream(vs, CompressionMode.Decompress).CopyTo(imagestream);
                                    }
                                    //mipmaps
                                    // mipmap data <offset, size>
                                    var mipmapoffsets = new List <Tuple <long, long> >();
                                    foreach (var mipinfo in MipMapInfo)
                                    {
                                        var beginoffset = mipmapstream.Position;

                                        using (var tempvs = file.CreateViewStream(mipinfo.Offset, mipinfo.ZSize, MemoryMappedFileAccess.Read))
                                        {
                                            new ZlibStream(tempvs, CompressionMode.Decompress).CopyTo(mipmapstream);
                                        }
                                        mipmapoffsets.Add(new Tuple <long, long>(beginoffset, mipmapstream.Position - beginoffset));
                                    }

                                    //assemble faces
                                    for (int i = 0; i < 6; i++)
                                    {
                                        // get one face
                                        var offset   = 0 + (i * imagestream.Length / 6);
                                        var facesize = (int)imagestream.Length / 6;

                                        imagereader.BaseStream.Seek(offset, SeekOrigin.Begin);
                                        var face = imagereader.ReadBytes(facesize);
                                        output.Write(face, 0, face.Length);

                                        // get mipmaps for face
                                        foreach (var o in mipmapoffsets)
                                        {
                                            var mipsize = (o.Item2 / 6);
                                            var moffset = o.Item1 + (i * mipsize);

                                            mipmapreader.BaseStream.Seek(moffset, SeekOrigin.Begin);
                                            var mipmap = mipmapreader.ReadBytes((int)(mipsize));

                                            output.Write(mipmap, 0, mipmap.Length);
                                        }
                                    }
                                }
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="inputfolder"></param>
        public void LoadFiles(string inputfolder, ILoggerService logger = null)
        {
            var di = new DirectoryInfo(inputfolder);

            if (!di.Exists)
            {
                return;
            }
            var inputfiles = di.GetFiles("*.dds", SearchOption.AllDirectories)
                             .Select(_ => _.FullName).ToList();

            logger?.LogString($"[TextureCache] Begin caching.", Logtype.Important);
            logger?.LogString($"[TextureCache] Found {inputfiles.Count} files.", Logtype.Important);

            // clear data
            Files.Clear();
            Names.Clear();
            MipOffsets.Clear();

            foreach (var filename in inputfiles)
            {
                var ext = Path.GetExtension(filename);

                switch (ext)
                {
                //case ".xbm":
                //    {
                //        // read cr2wfile
                //        var cr2w = new CR2WFile()
                //        {
                //            FileName = filename,
                //        };
                //        using (var cfs = new FileStream(filename, FileMode.Open, FileAccess.Read))
                //        using (var reader = new BinaryReader(cfs))
                //        {
                //            var errorcode = cr2w.Read(reader);
                //            if (errorcode != EFileReadErrorCodes.NoError)
                //                continue;
                //        }

                //        // check if CBitmapTexture
                //        if (!(cr2w.chunks.FirstOrDefault()?.data is CBitmapTexture xbm))
                //        {
                //            continue;
                //        }

                //        break;
                //    }
                case ".DDS":
                case ".dds":
                {
                    var ddsheader = DDSUtils.ReadHeader(filename);

                    var redpath      = Path.ChangeExtension(filename, ddsheader.Iscubemap ? ".w2cube" : ".xbm");
                    var relativepath = redpath.Substring(di.FullName.Length + 1);

                    #region Create Table Item

                    var(type1, type2) =
                        CommonImageTools.GetREDEngineByteFromEFormat(ddsheader.Format);

                    if (ddsheader.Width % 2 != 0 || ddsheader.Height % 2 != 0)
                    {
                        continue;
                    }

                    var maxSide = Math.Max(ddsheader.Width, ddsheader.Height);
                    //var minSide = Math.Min(ddsheader.Width, ddsheader.Height);
                    var realmipscount = Math.Max(1, Math.Log10(maxSide / 32) / Math.Log10(2));
                    if (ddsheader.Mipscount == 1)     //TODO: fix this
                    {
                        realmipscount = 0;
                    }
                    if (ddsheader.Mipscount == 0)     //TODO: fix this
                    {
                        realmipscount = 0;
                    }

                    var ti = new TextureCacheItem(this)
                    {
                        Name     = relativepath,
                        FullName = filename,

                        Hash = relativepath.HashStringKey(),

                        /*------------- TextureCache Data ---------------*/
                        // NOTE: these need to be populated after writing the files
                        ParentFile        = "",    //done
                        StringTableOffset = -1,    //done
                        PageOffset        = 0,     //done
                        CompressedSize    = 0,     //done
                        UncompressedSize  = 0,     //done
                        MipOffsetIndex    = 0,     //done

                        /*------------- Image data ---------------*/
                        NumMipOffsets = (int)realmipscount,
                        BaseAlignment = ddsheader.Bpp,
                        BaseWidth     = (ushort)ddsheader.Width,
                        BaseHeight    = (ushort)ddsheader.Height,
                        Mipcount      = (ushort)Math.Max(1, ddsheader.Mipscount),
                        SliceCount    = (ushort)ddsheader.Slicecount,     //TODO

                        TimeStamp = 0 /*(long)CDateTime.Now.ToUInt64()*/, //NOTE: Not even CDPR could be bothered to use their own Timestamps

                        Type1  = type1,
                        Type2  = type2,
                        IsCube = ddsheader.Iscubemap ? (byte)1 : (byte)0,
                        Unk1   = 0x00,   //TODO: figure this out

                        Format = CommonImageTools.GetEFormatFromREDEngineByte(type1)
                    };

                    #endregion Create Table Item

                    Files.Add(ti);
                    Names.Add(ti.Name);

                    logger?.LogString($"Cached {ti.Name}", Logtype.Normal);

                    break;
                }
                }
            }

            logger?.LogString($"[TextureCache] Caching successful.", Logtype.Success);
        }