public void GetPreview() { DdsFile dds; CSharpImageLibrary.ImageEngineImage image = null; try { this.Preview = null; dds = new DdsFile(Texture, false); dds.Write(File.Open(System.AppDomain.CurrentDomain.BaseDirectory + "\\temp.dds", FileMode.Create, FileAccess.ReadWrite, FileShare.Read), -1); int maxDimension = (int)Math.Max(dds.header.width, dds.header.height); image = new CSharpImageLibrary.ImageEngineImage(System.AppDomain.CurrentDomain.BaseDirectory + "\\temp.dds", maxDimension); Preview = null; this.Preview = image.GetWPFBitmap(maxDimension, true); this.PreviewErrorVisibility = Visibility.Collapsed; OnPropertyChanged(nameof(Width)); OnPropertyChanged(nameof(Height)); OnPropertyChanged(nameof(TextureInfo)); } catch (Exception ex) { Preview = null; this.PreviewError = "Could not create preview! Export/Import may still work in certain circumstances." + Environment.NewLine + Environment.NewLine + ex.Message; this.PreviewErrorVisibility = Visibility.Visible; } finally { dds = null; image?.Dispose(); image = null; } }
/// <summary> /// Encodes all mipmap levels into a ktx or a dds file and writes it to the output stream. /// </summary> public void Encode(Image <Rgba32> inputImage, Stream outputStream) { if (OutputOptions.fileFormat == OutputFileFormat.Ktx) { KtxFile output = EncodeToKtx(inputImage); output.Write(outputStream); } else if (OutputOptions.fileFormat == OutputFileFormat.Dds) { DdsFile output = EncodeToDds(inputImage); output.Write(outputStream); } }
/// <summary> /// Encodes all cubemap faces and mipmap levels into Ktx file and writes it to the output stream. /// Order is +X, -X, +Y, -Y, +Z, -Z /// </summary> public void EncodeCubeMap(Image <Rgba32> right, Image <Rgba32> left, Image <Rgba32> top, Image <Rgba32> down, Image <Rgba32> back, Image <Rgba32> front, Stream outputStream) { if (OutputOptions.fileFormat == OutputFileFormat.Ktx) { KtxFile output = EncodeCubeMapToKtx(right, left, top, down, back, front); output.Write(outputStream); } else if (OutputOptions.fileFormat == OutputFileFormat.Dds) { DdsFile output = EncodeCubeMapToDds(right, left, top, down, back, front); output.Write(outputStream); } }
private static void UnpackFtexFile(string filePath, string outputPath) { string fileDirectory = string.IsNullOrEmpty(outputPath) ? Path.GetDirectoryName(filePath) ?? string.Empty : outputPath; string fileName = Path.GetFileNameWithoutExtension(filePath); FtexFile ftexFile = GetFtexFile(filePath); DdsFile ddsFile = FtexDdsConverter.ConvertToDds(ftexFile); string ddsFileName = $"{fileName}.dds"; string ddsFilePath = Path.Combine(fileDirectory, ddsFileName); using (FileStream outputStream = new FileStream(ddsFilePath, FileMode.Create)) { ddsFile.Write(outputStream); } }
private void ExportTextures_Execute(object parameter) { try { Directory.CreateDirectory(mainView.FilePath.Replace(".", "_") + "_textures"); DdsFile dds; foreach (PssgTextureViewModel texView in Textures) { dds = new DdsFile(texView.Texture, false); dds.Write(File.Open(mainView.FilePath.Replace(".", "_") + "_textures" + "\\" + texView.Texture.GetAttribute("id").DisplayValue + ".dds", FileMode.Create), -1); } MessageBox.Show("Textures exported successfully!", "Success", MessageBoxButton.OK, MessageBoxImage.Information); } catch { MessageBox.Show("There was an error, could not export all textures!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
public void Write(Stream outputStream) { if (Data == null) { return; } byte[] data = Data; if (GameVersion == GameVersion.Bloodborne) { DxgiFormat dxgiFormat = (DxgiFormat)DxgiFormat; DdsPixelFormat pixelFormat = DdsPixelFormat.DxgiToDdsPixelFormat(dxgiFormat); DdsFile ddsFile = new DdsFile { Header = new DdsFileHeader { Flags = DdsFileHeaderFlags.Texture | (MipMapCount > 1 ? DdsFileHeaderFlags.MipMap : 0), Height = Height, Width = Width, Depth = 0, PitchOrLinearSize = Data.Length, MipMapCount = MipMapCount, PixelFormat = pixelFormat, Caps = DdsSurfaceFlags.Texture | (MipMapCount > 1 ? DdsSurfaceFlags.MipMap : 0) }, HeaderDx10 = pixelFormat.FourCc != DdsPixelFormat.Dx10FourCc ? null : new DdsFileHeaderDx10 { Format = dxgiFormat, ResourceDimension = D3D10ResourceDimension.Texture2D, MiscFlag = 0, ArraySize = 1, MiscFlags2 = 0 }, Data = DdsFile.ConvertData(data, Height, Width, dxgiFormat) }; ddsFile.Write(outputStream); } else { outputStream.Write(data, 0, data.Length); } }
private void Export_Execute(object parameter) { PssgNode node = ((PssgTextureViewModel)parameter).Texture; SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "Dds files|*.dds|All files|*.*"; dialog.Title = "Select the dds save location and file name"; dialog.FileName = node.Attributes["id"].DisplayValue + ".dds"; if (dialog.ShowDialog() == true) { try { DdsFile dds = new DdsFile(node, false); dds.Write(File.Open(dialog.FileName, FileMode.Create), -1); } catch (Exception ex) { MessageBox.Show("Could not export texture!" + Environment.NewLine + Environment.NewLine + ex.Message, "Export Failed", MessageBoxButton.OK, MessageBoxImage.Error); } } }
private void ImportTextures_Execute(object parameter) { try { string directory = mainView.FilePath.Replace(".", "_") + "_textures"; if (Directory.Exists(directory) == true) { DdsFile dds; foreach (string filePath in Directory.GetFiles(directory, "*.dds")) { foreach (PssgTextureViewModel texView in Textures) { if (Path.GetFileNameWithoutExtension(filePath) == texView.Texture.GetAttribute("id").ToString()) { dds = new DdsFile(File.Open(filePath, FileMode.Open)); dds.Write(texView.Texture); if (texView.IsSelected) { texView.GetPreview(); } break; } } } MessageBox.Show("Textures imported successfully!", "Success", MessageBoxButton.OK, MessageBoxImage.Information); } else { MessageBox.Show("Could not find textures folder!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } catch { MessageBox.Show("There was an error, could not import all textures!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
private void Import_Execute(object parameter) { PssgTextureViewModel texView = (PssgTextureViewModel)parameter; PssgNode node = texView.Texture; OpenFileDialog dialog = new OpenFileDialog(); dialog.Filter = "Dds files|*.dds|All files|*.*"; dialog.Title = "Select a dds file"; dialog.FileName = node.Attributes["id"].DisplayValue + ".dds"; if (dialog.ShowDialog() == true) { try { DdsFile dds = new DdsFile(File.Open(dialog.FileName, FileMode.Open)); dds.Write(node); texView.GetPreview(); } catch (Exception ex) { MessageBox.Show("Could not import texture!" + Environment.NewLine + Environment.NewLine + ex.Message, "Import Failed", MessageBoxButton.OK, MessageBoxImage.Error); } } }
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); }