public override void FromFragment(ErpFragment fragment)
        {
            using (var memData = fragment.GetDataStream(true))
                using (ErpBinaryReader reader = new ErpBinaryReader(memData))
                {
                    Unknown     = reader.ReadInt32();
                    Unknown2    = reader.ReadInt32();
                    ImageType   = (ErpGfxSurfaceFormat)reader.ReadInt32();
                    Width       = reader.ReadUInt32();
                    Height      = reader.ReadUInt32();
                    Unknown3    = reader.ReadInt32();
                    MipMapCount = reader.ReadUInt32();
                    ArraySize   = reader.ReadUInt32();
                    Unknown4    = reader.ReadInt32();

                    _leftoverBytes = reader.BaseStream.Length - reader.BaseStream.Position;
                    if (_leftoverBytes == 4)
                    {
                        // noticed this extra field in F1 2020, not sure if in earlier ones
                        Unknown5 = reader.ReadInt32();
                    }
                    else if (_leftoverBytes > 0)
                    {
                        throw new NotSupportedException("The GfxSurfaceRes0 data is not supported.");
                    }
                }
        }
        public override void FromFragment(ErpFragment fragment)
        {
            using (var memData = fragment.GetDataStream(true))
                using (ErpBinaryReader reader = new ErpBinaryReader(memData))
                {
                    MipMapFileName = reader.ReadString(reader.ReadByte());
                    UInt32 mipMapCount = reader.ReadUInt32();

                    Mips = new List <ErpGfxSurfaceRes2Mips>((int)mipMapCount);
                    for (int i = 0; i < mipMapCount; ++i)
                    {
                        ErpGfxSurfaceRes2Mips mip = new ErpGfxSurfaceRes2Mips();
                        mip.Compression = (ErpCompressionAlgorithm)reader.ReadByte();
                        mip.Offset      = reader.ReadUInt64();
                        mip.PackedSize  = reader.ReadUInt64();
                        mip.Size        = reader.ReadUInt64();
                        Mips.Add(mip);
                    }

                    long leftoverBytes = reader.BaseStream.Length - reader.BaseStream.Position;
                    if (leftoverBytes == 8)
                    {
                        // This part was introduced in F1 2017
                        hasTwoUnknowns = true;
                        Unknown        = reader.ReadSingle();
                        Unknown2       = reader.ReadSingle();
                    }
                    else if (leftoverBytes > 0)
                    {
                        throw new NotSupportedException("The GfxSurfaceRes2 data is not supported.");
                    }
                }
        }
Example #3
0
        public override void FromFragment(ErpFragment fragment)
        {
            using (var memData = fragment.GetDataStream(true))
                using (ErpBinaryReader reader = new ErpBinaryReader(memData))
                {
                    MipMapFileName = reader.ReadString(reader.ReadByte());
                    UInt32 mipMapCount = reader.ReadUInt32();

                    Mips = new List <ErpGfxSurfaceRes2Mips>((int)mipMapCount);
                    for (int i = 0; i < mipMapCount; ++i)
                    {
                        ErpGfxSurfaceRes2Mips mip = new ErpGfxSurfaceRes2Mips();
                        mip.Compression = (ErpCompressionAlgorithm)reader.ReadByte();
                        mip.Offset      = reader.ReadUInt64();
                        mip.PackedSize  = reader.ReadUInt64();
                        mip.Size        = reader.ReadUInt64();
                        Mips.Add(mip);
                    }

                    // This part was introduces in F1 2017
                    if (reader.BaseStream.Length - reader.BaseStream.Position == 8)
                    {
                        hasTwoUnknowns = true;
                        Unknown        = reader.ReadSingle();
                        Unknown2       = reader.ReadSingle();
                    }
                }
        }
Example #4
0
 public override void FromFragment(ErpFragment fragment)
 {
     using var memData   = fragment.GetDataStream(true);
     using var reader    = new ErpBinaryReader(memData);
     Unknown             = reader.ReadInt32();
     ImageType           = (ErpGfxSurfaceFormat)reader.ReadInt32();
     Unknown2            = reader.ReadInt32();
     MipMapCount         = reader.ReadUInt32();
     Unknown3            = reader.ReadInt32();
     Unknown4            = reader.ReadInt32();
     SurfaceResourceName = reader.ReadString();
 }
Example #5
0
 public override void FromFragment(ErpFragment fragment)
 {
     using (var memData = fragment.GetDataStream(true))
         using (ErpBinaryReader reader = new ErpBinaryReader(memData))
         {
             Unknown     = reader.ReadInt32();
             Unknown2    = reader.ReadInt32();
             ImageType   = (ErpGfxSurfaceFormat)reader.ReadInt32();
             Width       = reader.ReadUInt32();
             Height      = reader.ReadUInt32();
             Unknown3    = reader.ReadInt32();
             MipMapCount = reader.ReadUInt32();
             ArraySize   = reader.ReadUInt32();
             Unknown4    = reader.ReadInt32();
         }
 }
Example #6
0
        public override void FromFragment(ErpFragment fragment)
        {
            using (var memData = fragment.GetDataStream(true))
                using (ErpBinaryReader reader = new ErpBinaryReader(memData))
                {
                    MipMapFileName = reader.ReadString(reader.ReadByte());
                    UInt32 mipMapCount = reader.ReadUInt32();

                    Mips = new List <ErpGfxSurfaceRes2Mips>((int)mipMapCount);
                    for (int i = 0; i < mipMapCount; ++i)
                    {
                        ErpGfxSurfaceRes2Mips mip = new ErpGfxSurfaceRes2Mips();
                        mip.Unknown = reader.ReadByte();
                        mip.Offset  = reader.ReadUInt64();
                        mip.Width   = reader.ReadUInt64();
                        mip.Height  = reader.ReadUInt64();
                        Mips.Add(mip);
                    }
                }
        }
 public abstract void Read(ErpBinaryReader reader);
 public override void Read(ErpBinaryReader reader)
 {
     throw new NotImplementedException();
 }
Example #9
0
        public DdsFile ExportDDS(string fileName, bool isPreview, bool exportTexArray)
        {
            DdsFile dds = new DdsFile();

            ErpGfxSRVResource srvRes = new ErpGfxSRVResource();

            srvRes.FromResource(Texture);

            uint  mipPower = (uint)Math.Pow(2.0, srvRes.SurfaceRes.Frag2.Mips.Count);
            uint  mipWidth = 0, mipHeight = 0;
            ulong mipLinearSize = 0;
            ulong mipTotalSize  = 0;

            if (srvRes.SurfaceRes.HasMips)
            {
                mipLinearSize = Math.Max(srvRes.SurfaceRes.Frag2.Mips[0].Width, srvRes.SurfaceRes.Frag2.Mips[0].Height);
                for (int i = 0; i < srvRes.SurfaceRes.Frag2.Mips.Count; ++i)
                {
                    mipTotalSize += Math.Max(srvRes.SurfaceRes.Frag2.Mips[i].Width, srvRes.SurfaceRes.Frag2.Mips[i].Height);
                }

                mipWidth  = srvRes.SurfaceRes.Fragment0.Width * mipPower;
                mipHeight = srvRes.SurfaceRes.Fragment0.Height * mipPower;
            }

            dds.header.width       = srvRes.SurfaceRes.Fragment0.Width;
            dds.header.height      = srvRes.SurfaceRes.Fragment0.Height;
            dds.header10.arraySize = srvRes.SurfaceRes.Fragment0.ArraySize;
            _texArraySize          = srvRes.SurfaceRes.Fragment0.ArraySize;
            _textureInfo           = srvRes.SurfaceRes.Fragment0.Width + "x" + srvRes.SurfaceRes.Fragment0.Height + " Mips:" + (srvRes.SurfaceRes.Fragment0.MipMapCount) + " Format:" + srvRes.SurfaceRes.Fragment0.ImageType + ",";
            switch (srvRes.SurfaceRes.Fragment0.ImageType)
            {
            //case (ErpGfxSurfaceFormat)14: // gameparticles k_smoke; application
            case ErpGfxSurfaceFormat.ABGR8:
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height) * 4;

                if (srvRes.SurfaceRes.Fragment0.ArraySize > 1 && exportTexArray)
                {
                    dds.header.ddspf.flags |= DdsPixelFormat.Flags.DDPF_FOURCC;
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                    dds.header10.dxgiFormat = DXGI_Format.DXGI_FORMAT_R8G8B8A8_UNORM;
                    TextureInfo            += "RGBA8";
                }
                else
                {
                    dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_ALPHAPIXELS | DdsPixelFormat.Flags.DDPF_RGB;
                    dds.header.ddspf.fourCC      = 0;
                    dds.header.ddspf.rGBBitCount = 32;
                    dds.header.ddspf.rBitMask    = 0xFF;
                    dds.header.ddspf.gBitMask    = 0xFF00;
                    dds.header.ddspf.bBitMask    = 0xFF0000;
                    dds.header.ddspf.aBitMask    = 0xFF000000;
                    TextureInfo += "ABGR8";
                }
                break;

            case ErpGfxSurfaceFormat.DXT1:     // ferrari_wheel_sfc
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height) / 2;
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;

                if (srvRes.SurfaceRes.Fragment0.ArraySize > 1 && exportTexArray)
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                    dds.header10.dxgiFormat = DXGI_Format.DXGI_FORMAT_BC1_UNORM;
                }
                else
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DXT1"), 0);
                }

                TextureInfo += "DXT1";
                break;

            case ErpGfxSurfaceFormat.DXT1_SRGB:     // ferrari_wheel_df, ferrari_paint
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height) / 2;
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;
                dds.header.ddspf.fourCC      = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                dds.header10.dxgiFormat      = DXGI_Format.DXGI_FORMAT_BC1_UNORM_SRGB;
                TextureInfo += "BC1_SRGB";
                break;

            case ErpGfxSurfaceFormat.DXT5:     // ferrari_sfc
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height);
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;

                if (srvRes.SurfaceRes.Fragment0.ArraySize > 1 && exportTexArray)
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                    dds.header10.dxgiFormat = DXGI_Format.DXGI_FORMAT_BC3_UNORM;
                }
                else
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DXT5"), 0);
                }

                TextureInfo += "DXT5";
                break;

            case ErpGfxSurfaceFormat.DXT5_SRGB:     // ferrari_decal
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height);
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;
                dds.header.ddspf.fourCC      = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                dds.header10.dxgiFormat      = DXGI_Format.DXGI_FORMAT_BC3_UNORM_SRGB;
                TextureInfo += "BC3_SRGB";
                break;

            case ErpGfxSurfaceFormat.ATI1:     // gameparticles k_smoke
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height) / 2;
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;

                if (srvRes.SurfaceRes.Fragment0.ArraySize > 1 && exportTexArray)
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                    dds.header10.dxgiFormat = DXGI_Format.DXGI_FORMAT_BC4_UNORM;
                }
                else
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("ATI1"), 0);
                }

                TextureInfo += "ATI1";
                break;

            case ErpGfxSurfaceFormat.ATI2:     // ferrari_wheel_nm
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height);
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;

                if (srvRes.SurfaceRes.Fragment0.ArraySize > 1 && exportTexArray)
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                    dds.header10.dxgiFormat = DXGI_Format.DXGI_FORMAT_BC5_UNORM;
                }
                else
                {
                    dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("ATI2"), 0);
                }

                TextureInfo += "ATI2/3Dc";
                break;

            case ErpGfxSurfaceFormat.BC6:     // key0_2016; environment abu_dhabi tree_palm_06
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height);
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;
                dds.header.ddspf.fourCC      = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                dds.header10.dxgiFormat      = DXGI_Format.DXGI_FORMAT_BC6H_UF16;
                TextureInfo += "BC6H_UF16";
                break;

            case ErpGfxSurfaceFormat.BC7:
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height);
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;
                dds.header.ddspf.fourCC      = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                dds.header10.dxgiFormat      = DXGI_Format.DXGI_FORMAT_BC7_UNORM;
                TextureInfo += "BC7";
                break;

            case ErpGfxSurfaceFormat.BC7_SRGB:     // flow_boot splash_bg_image
                dds.header.flags            |= DdsHeader.Flags.DDSD_LINEARSIZE;
                dds.header.pitchOrLinearSize = (srvRes.SurfaceRes.Fragment0.Width * srvRes.SurfaceRes.Fragment0.Height);
                dds.header.ddspf.flags      |= DdsPixelFormat.Flags.DDPF_FOURCC;
                dds.header.ddspf.fourCC      = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DX10"), 0);
                dds.header10.dxgiFormat      = DXGI_Format.DXGI_FORMAT_BC7_UNORM_SRGB;
                TextureInfo += "BC7_SRGB";
                break;

            default:
                TextureInfo += "Unknown";
                throw new Exception("Image format not supported!");
            }
            if (srvRes.SurfaceRes.Fragment0.MipMapCount > 0)
            {
                dds.header.flags      |= DdsHeader.Flags.DDSD_MIPMAPCOUNT;
                dds.header.mipMapCount = srvRes.SurfaceRes.Fragment0.MipMapCount;
                dds.header.caps       |= DdsHeader.Caps.DDSCAPS_MIPMAP | DdsHeader.Caps.DDSCAPS_COMPLEX;
            }

            byte[] imageData = srvRes.SurfaceRes.Fragment1.Data;

            string mipMapFullFileName = Path.Combine(Properties.Settings.Default.F12016Dir, srvRes.SurfaceRes.Frag2.MipMapFileName);
            bool   foundMipMapFile    = File.Exists(mipMapFullFileName);
            bool   hasValidMipMaps    = dds.header.pitchOrLinearSize < mipLinearSize && dds.header.pitchOrLinearSize * mipPower * mipPower == mipLinearSize;

            if (srvRes.SurfaceRes.HasMips && hasValidMipMaps && (!isPreview || foundMipMapFile))
            {
                if (!isPreview)
                {
                    OpenFileDialog odialog = new OpenFileDialog();
                    odialog.Filter     = "Mipmaps files|*.mipmaps|All files|*.*";
                    odialog.Title      = "Select a mipmaps file";
                    odialog.FileName   = Path.GetFileName(mipMapFullFileName);
                    mipMapFullFileName = Path.GetDirectoryName(mipMapFullFileName);
                    if (Directory.Exists(mipMapFullFileName))
                    {
                        odialog.InitialDirectory = mipMapFullFileName;
                    }

                    foundMipMapFile    = odialog.ShowDialog() == true;
                    mipMapFullFileName = odialog.FileName;
                }

                if (foundMipMapFile)
                {
                    byte[] mipImageData;
                    using (ErpBinaryReader reader = new ErpBinaryReader(File.Open(mipMapFullFileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
                    {
                        mipImageData = reader.ReadBytes((int)reader.BaseStream.Length);
                    }

                    dds.header.width             = mipWidth;
                    dds.header.height            = mipHeight;
                    dds.header.pitchOrLinearSize = (uint)mipLinearSize;

                    if (mipTotalSize != (ulong)mipImageData.Length)
                    {
                        throw new Exception($"There is a mismatch with the mipmaps file.{Environment.NewLine}It is either incorrectly modded, or in the wrong folder.");
                    }


                    if (srvRes.SurfaceRes.Frag2.Mips.Count > 0)
                    {
                        dds.header.flags       |= DdsHeader.Flags.DDSD_MIPMAPCOUNT;
                        dds.header.mipMapCount += (uint)srvRes.SurfaceRes.Frag2.Mips.Count;
                        dds.header.caps        |= DdsHeader.Caps.DDSCAPS_MIPMAP | DdsHeader.Caps.DDSCAPS_COMPLEX;
                    }

                    dds.bdata = new byte[mipImageData.Length + imageData.Length];
                    Buffer.BlockCopy(mipImageData, 0, dds.bdata, 0, mipImageData.Length);
                    Buffer.BlockCopy(imageData, 0, dds.bdata, mipImageData.Length, imageData.Length);
                    dds.Write(File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Read), -1);
                    TextureInfo += Environment.NewLine + mipWidth + "x" + mipHeight + " Mips:" + (srvRes.SurfaceRes.Frag2.Mips.Count);
                }
                else
                {
                    throw new FileNotFoundException("Mipmaps file not found!", mipMapFullFileName);
                }
            }
            else
            {
                if (srvRes.SurfaceRes.HasMips)
                {
                    if (!hasValidMipMaps)
                    {
                        // This usually happens when the mips fragment was never updated with the new offsets/width/height/linearsize
                        TextureInfo += Environment.NewLine + "Mipmaps are incorrectly modded! Try exporting, then importing to fix the issue.";
                    }
                    else if (!foundMipMapFile)
                    {
                        TextureInfo += Environment.NewLine + "Mipmaps not found! Make sure they are in the correct F1 game folder!";
                    }
                    else
                    {
                        // Not found during preview
                        TextureInfo += Environment.NewLine + "Mipmaps not loaded! Make sure they are in the correct F1 game folder!";
                    }
                }

                if (srvRes.SurfaceRes.Fragment0.ArraySize > 1)
                {
                    uint   bytesPerArrayImage = (uint)imageData.Length / srvRes.SurfaceRes.Fragment0.ArraySize;
                    byte[] data = new byte[bytesPerArrayImage];

                    if (!exportTexArray)
                    {
                        dds.header10.arraySize = 1;
                        Buffer.BlockCopy(imageData, (int)(bytesPerArrayImage * _texArrayIndex), data, 0, (int)bytesPerArrayImage);
                        dds.bdata = data;
                        dds.Write(File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Read), -1);
                    }
                    else
                    {
                        dds.bdata = imageData;
                        dds.Write(File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Read), -1);

                        // TODO: Add support for exporting individual tex array slices
                        //string output = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName));
                        //for (int i = 0; i < srvRes.SurfaceRes.Fragment0.ArraySize; ++i)
                        //{
                        //    Buffer.BlockCopy(imageData, (int)(bytesPerArrayImage * i), data, 0, (int)bytesPerArrayImage);
                        //    dds.bdata = data;
                        //    dds.Write(File.Open(output + "!!!" + i.ToString("000") + ".dds", FileMode.Create, FileAccess.Write, FileShare.Read), -1);
                        //}
                    }
                }
                else
                {
                    dds.bdata = imageData;
                    dds.Write(File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Read), -1);
                }
            }

            return(dds);
        }