using System; using System.Collections.Generic; using System.Linq; using System.Drawing; using System.Threading.Tasks; using System.Windows.Forms; using Switch_Toolbox.Library; using Switch_Toolbox.Library.Forms; using Syroot.NintenTools.Bfres; using Syroot.NintenTools.Bfres.GX2; using OpenTK; using OpenTK.Graphics.OpenGL; using Smash_Forge.Rendering; using WeifenLuo.WinFormsUI.Docking; namespace FirstPlugin { public class FTEXContainer : TreeNodeCustom { public Dictionary Textures = new Dictionary(); //To get instance of classes public FTEXContainer() { Text = "Textures"; Name = "FTEXCONT"; ContextMenu = new ContextMenu(); MenuItem importTex = new MenuItem("Import"); ContextMenu.MenuItems.Add(importTex); importTex.Click += Import; MenuItem exportAll = new MenuItem("Export All Textures"); ContextMenu.MenuItems.Add(exportAll); exportAll.Click += ExportAll; MenuItem clear = new MenuItem("Clear"); ContextMenu.MenuItems.Add(clear); clear.Click += Clear; } private void Clear(object sender, EventArgs args) { Nodes.Clear(); Textures.Clear(); } public void RefreshGlTexturesByName() { } public override void OnClick(TreeView treeview) { } public void RemoveTexture(FTEX textureData) { Nodes.Remove(textureData); Textures.Remove(textureData.Text); Viewport.Instance.UpdateViewport(); } private void Import(object sender, EventArgs args) { ImportTexture(); } public void ImportTexture() { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "Supported Formats|*.dds; *.png;*.tga;*.jpg;*.tiff|" + "Microsoft DDS |*.dds|" + "Portable Network Graphics |*.png|" + "Joint Photographic Experts Group |*.jpg|" + "Bitmap Image |*.bmp|" + "Tagged Image File Format |*.tiff|" + "All files(*.*)|*.*"; ofd.Multiselect = true; if (ofd.ShowDialog() == DialogResult.OK) { GTXTextureImporter importer = new GTXTextureImporter(); List settings = new List(); foreach (string name in ofd.FileNames) { string ext = System.IO.Path.GetExtension(name); ext = ext.ToLower(); if (ext == ".dds") { settings.Add(LoadSettings(name)); if (settings.Count == 0) { importer.Dispose(); return; } importer.LoadSettings(settings); foreach (var setting in settings) { if (setting.DataBlockOutput != null) { GTX.GX2Surface tex = setting.CreateGx2Texture(setting.DataBlockOutput[0]); FTEX ftex = new FTEX(); ftex.texture = ftex.FromGx2Surface(tex, setting); ftex.Read(ftex.texture); Nodes.Add(ftex); Textures.Add(ftex.Text, ftex); ftex.LoadOpenGLTexture(); } } } else { settings.Add(LoadSettings(name)); if (settings.Count == 0) { importer.Dispose(); return; } importer.LoadSettings(settings); if (importer.ShowDialog() == DialogResult.OK) { Cursor.Current = Cursors.WaitCursor; foreach (var setting in settings) { if (setting.GenerateMipmaps) { setting.DataBlockOutput.Clear(); setting.DataBlockOutput.Add(setting.GenerateMips()); } if (setting.DataBlockOutput != null) { GTX.GX2Surface tex = setting.CreateGx2Texture(setting.DataBlockOutput[0]); FTEX ftex = new FTEX(); ftex.texture = ftex.FromGx2Surface(tex, setting); ftex.Read(ftex.texture); Nodes.Add(ftex); Textures.Add(ftex.Text, ftex); ftex.LoadOpenGLTexture(); } else { MessageBox.Show("Something went wrong???"); } } } } settings.Clear(); GC.Collect(); Cursor.Current = Cursors.Default; } } } public GTXImporterSettings LoadSettings(string name) { var importer = new GTXImporterSettings(); string ext = System.IO.Path.GetExtension(name); ext = ext.ToLower(); switch (ext) { case ".dds": importer.LoadDDS(name); break; default: importer.LoadBitMap(name); break; } return importer; } private void ExportAll(object sender, EventArgs args) { List Formats = new List(); Formats.Add("Cafe Binary Textures (.bftex)"); Formats.Add("Microsoft DDS (.dds)"); Formats.Add("Portable Graphics Network (.png)"); Formats.Add("Joint Photographic Experts Group (.jpg)"); Formats.Add("Bitmap Image (.bmp)"); Formats.Add("Tagged Image File Format (.tiff)"); FolderSelectDialog sfd = new FolderSelectDialog(); if (sfd.ShowDialog() == DialogResult.OK) { string folderPath = sfd.SelectedPath; TextureFormatExport form = new TextureFormatExport(Formats); if (form.ShowDialog() == DialogResult.OK) { foreach (FTEX tex in Nodes) { if (form.Index == 0) tex.SaveBinaryTexture(folderPath + '\\' + tex.Text + ".bftex"); else if (form.Index == 1) tex.SaveDDS(folderPath + '\\' + tex.Text + ".dds"); else if (form.Index == 2) tex.SaveBitMap(folderPath + '\\' + tex.Text + ".png"); else if (form.Index == 3) tex.SaveBitMap(folderPath + '\\' + tex.Text + ".jpg"); else if (form.Index == 4) tex.SaveBitMap(folderPath + '\\' + tex.Text + ".bmp"); else if (form.Index == 5) tex.SaveBitMap(folderPath + '\\' + tex.Text + ".tiff"); } } } } } public class FTEX : TreeNodeCustom { public int format; public RenderableTex renderedTex = new RenderableTex(); public Texture texture; public FTEX() { ContextMenu = new ContextMenu(); MenuItem export = new MenuItem("Export"); ContextMenu.MenuItems.Add(export); export.Click += Export; MenuItem replace = new MenuItem("Replace"); ContextMenu.MenuItems.Add(replace); replace.Click += Replace; MenuItem remove = new MenuItem("Remove"); ContextMenu.MenuItems.Add(remove); remove.Click += Remove; MenuItem rename = new MenuItem("Rename"); ContextMenu.MenuItems.Add(rename); rename.Click += Rename; } private void Replace(object sender, EventArgs args) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "Supported Formats|*.dds; *.png;*.tga;*.jpg;*.tiff|" + "Microsoft DDS |*.dds|" + "Portable Network Graphics |*.png|" + "Joint Photographic Experts Group |*.jpg|" + "Bitmap Image |*.bmp|" + "Tagged Image File Format |*.tiff|" + "All files(*.*)|*.*"; ofd.Multiselect = false; if (ofd.ShowDialog() == DialogResult.OK) { Replace(ofd.FileName); } } public void Replace(string FileName) { string ext = System.IO.Path.GetExtension(FileName); ext = ext.ToLower(); GTXImporterSettings setting = new GTXImporterSettings(); GTXTextureImporter importer = new GTXTextureImporter(); switch (ext) { case ".dds": setting.LoadDDS(FileName, null); break; default: setting.LoadBitMap(FileName); importer.LoadSetting(setting); break; } if (importer.ShowDialog() == DialogResult.OK) { Cursor.Current = Cursors.WaitCursor; if (setting.GenerateMipmaps) { setting.DataBlockOutput.Clear(); setting.DataBlockOutput.Add(setting.GenerateMips()); } if (setting.DataBlockOutput != null) { var surface = setting.CreateGx2Texture(setting.DataBlockOutput[0]); texture = FromGx2Surface(surface, setting); LoadOpenGLTexture(); } else { MessageBox.Show("Something went wrong???"); } UpdateEditor(); } } //We reuse GX2 data as it's the same thing public Texture FromGx2Surface(GTX.GX2Surface surf, GTXImporterSettings settings) { Texture tex = new Texture(); tex.Name = settings.TexName; tex.AAMode = (GX2AAMode)surf.aa; tex.Alignment = (uint)surf.alignment; tex.ArrayLength = 1; tex.Data = surf.data; tex.MipData = surf.mipData; tex.Format = (GX2SurfaceFormat)surf.format; tex.Dim = (GX2SurfaceDim)surf.dim; tex.Use = (GX2SurfaceUse)surf.use; tex.TileMode = (GX2TileMode)surf.tileMode; tex.Swizzle = (uint)surf.swizzle; tex.Pitch = (uint)surf.pitch; tex.Depth = (uint)surf.depth; tex.MipCount = (uint)surf.numMips; tex.MipOffsets = surf.mipOffset; tex.Height = (uint)surf.height; tex.Width = (uint)surf.width; tex.Regs = new uint[0]; var channels = SetChannelsByFormat((GX2SurfaceFormat)surf.format); tex.CompSelR = channels[0]; tex.CompSelG = channels[1]; tex.CompSelB = channels[2]; tex.CompSelA = channels[3]; return tex; } private void Rename(object sender, EventArgs args) { RenameDialog dialog = new RenameDialog(); dialog.SetString(Text); if (dialog.ShowDialog() == DialogResult.OK) { ((FTEXContainer)Parent).Textures.Remove(Text); Text = dialog.textBox1.Text; ((FTEXContainer)Parent).Textures.Add(Text, this); } } private void Remove(object sender, EventArgs args) { ((FTEXContainer)Parent).RemoveTexture(this); } private void Export(object sender, EventArgs args) { SaveFileDialog sfd = new SaveFileDialog(); sfd.FileName = Text; sfd.DefaultExt = "bftex"; sfd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" + "Binary Texture |*.bftex|" + "Microsoft DDS |*.dds|" + "Portable Network Graphics |*.png|" + "Joint Photographic Experts Group |*.jpg|" + "Bitmap Image |*.bmp|" + "Tagged Image File Format |*.tiff|" + "All files(*.*)|*.*"; if (sfd.ShowDialog() == DialogResult.OK) { Export(sfd.FileName); } } public void Read(Texture tex) { ImageKey = "Texture"; SelectedImageKey = "Texture"; Text = tex.Name; renderedTex = new RenderableTex(); renderedTex.width = (int)tex.Width; renderedTex.height = (int)tex.Height; format = (int)tex.Format; int swizzle = (int)tex.Swizzle; int pitch = (int)tex.Pitch; uint bpp = GTX.surfaceGetBitsPerPixel((uint)format) >> 3; Console.WriteLine(tex.Width); Console.WriteLine(tex.Height); Console.WriteLine(tex.Format); Console.WriteLine(tex.Swizzle); Console.WriteLine(tex.Pitch); Console.WriteLine(tex.Alignment); Console.WriteLine(tex.Depth); Console.WriteLine(tex.Dim); Console.WriteLine(tex.MipCount); Console.WriteLine(tex.MipOffsets); Console.WriteLine(tex.AAMode); Console.WriteLine(tex.Use); GTX.GX2Surface surf = new GTX.GX2Surface(); surf.bpp = bpp; surf.height = tex.Height; surf.width = tex.Width; surf.aa = (uint)tex.AAMode; surf.alignment = tex.Alignment; surf.depth = tex.Depth; surf.dim = (uint)tex.Dim; surf.format = (uint)tex.Format; surf.use = (uint)tex.Use; surf.pitch = tex.Pitch; surf.data = tex.Data; surf.numMips = tex.MipCount; surf.mipOffset = tex.MipOffsets; surf.mipData = tex.MipData; surf.tileMode = (uint)tex.TileMode; surf.swizzle = tex.Swizzle; List mips = GTX.Decode(surf); renderedTex.mipmaps.Add(mips); renderedTex.data = renderedTex.mipmaps[0][0]; } public static GX2CompSel[] SetChannelsByFormat(GX2SurfaceFormat Format) { GX2CompSel[] channels = new GX2CompSel[4]; switch (Format) { case GX2SurfaceFormat.T_BC5_UNorm: case GX2SurfaceFormat.T_BC5_SNorm: channels[0] = GX2CompSel.ChannelR; channels[1] = GX2CompSel.ChannelG; channels[2] = GX2CompSel.Always0; channels[3] = GX2CompSel.Always1; break; case GX2SurfaceFormat.T_BC4_SNorm: case GX2SurfaceFormat.T_BC4_UNorm: channels[0] = GX2CompSel.ChannelR; channels[1] = GX2CompSel.ChannelR; channels[2] = GX2CompSel.ChannelR; channels[3] = GX2CompSel.ChannelR; break; default: channels[0] = GX2CompSel.ChannelR; channels[1] = GX2CompSel.ChannelG; channels[2] = GX2CompSel.ChannelB; channels[3] = GX2CompSel.Always1; break; } return channels; } public void Export(string FileName, bool ExportSurfaceLevel = false, bool ExportMipMapLevel = false, int SurfaceLevel = 0, int MipLevel = 0) { string ext = System.IO.Path.GetExtension(FileName); ext = ext.ToLower(); switch (ext) { case ".bftex": SaveBinaryTexture(FileName); break; case ".dds": SaveDDS(FileName); break; default: SaveBitMap(FileName); break; } } internal void SaveBitMap(string FileName, int SurfaceLevel = 0, int MipLevel = 0) { Bitmap bitMap = DisplayTexture(MipLevel, SurfaceLevel); bitMap.Save(FileName); } internal void SaveBinaryTexture(string FileName) { Console.WriteLine("Test"); // Texture.Export(FileName, bntxFile); } internal void SaveDDS(string FileName) { DDS dds = new DDS(); dds.header = new DDS.Header(); dds.header.width = (uint)renderedTex.width; dds.header.height = (uint)renderedTex.width; dds.header.mipmapCount = (uint)renderedTex.mipmaps[0].Count; dds.header.pitchOrLinearSize = (uint)renderedTex.mipmaps[0][0].Length; if (IsCompressedFormat((GX2SurfaceFormat)format)) dds.SetFlags(GetCompressedDXGI_FORMAT((GX2SurfaceFormat)format)); else dds.SetFlags(GetUncompressedDXGI_FORMAT((GX2SurfaceFormat)format)); dds.Save(dds, FileName, renderedTex.mipmaps); } public void LoadOpenGLTexture() { if (OpenTKSharedResources.SetupStatus == OpenTKSharedResources.SharedResourceStatus.Unitialized) return; switch (format) { case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_UNORM): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_SRGB): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_UNORM): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_SRGB): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt3Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_UNORM): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_SRGB): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt5Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_UNORM): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedRedRgtc1; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_SNORM): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedSignedRedRgtc1; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_UNORM): renderedTex.pixelInternalFormat = PixelInternalFormat.CompressedRgRgtc2; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_SNORM): //OpenTK doesn't load BC5 SNORM textures right so I'll use the same decompress method bntx has renderedTex.data = DDSCompressor.DecompressBC5(renderedTex.mipmaps[0][0], (int)renderedTex.width, (int)renderedTex.height, true, true); renderedTex.pixelInternalFormat = PixelInternalFormat.Rgba; renderedTex.pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM): renderedTex.pixelInternalFormat = PixelInternalFormat.Rgba; renderedTex.pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB): renderedTex.pixelInternalFormat = PixelInternalFormat.Rgba; renderedTex.pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; } renderedTex.display = loadImage(renderedTex); } public static int loadImage(RenderableTex t) { int texID = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, texID); if (t.pixelInternalFormat != PixelInternalFormat.Rgba) { GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, (InternalFormat)t.pixelInternalFormat, t.width, t.height, 0, getImageSize(t), t.data); //Debug.WriteLine(GL.GetError()); } else { GL.TexImage2D(TextureTarget.Texture2D, 0, t.pixelInternalFormat, t.width, t.height, 0, t.pixelFormat, PixelType.UnsignedByte, t.data); } GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); return texID; } public static int getImageSize(RenderableTex t) { switch (t.pixelInternalFormat) { case PixelInternalFormat.CompressedRgbaS3tcDxt1Ext: case PixelInternalFormat.CompressedSrgbAlphaS3tcDxt1Ext: case PixelInternalFormat.CompressedRedRgtc1: case PixelInternalFormat.CompressedSignedRedRgtc1: return (t.width * t.height / 2); case PixelInternalFormat.CompressedRgbaS3tcDxt3Ext: case PixelInternalFormat.CompressedSrgbAlphaS3tcDxt3Ext: case PixelInternalFormat.CompressedRgbaS3tcDxt5Ext: case PixelInternalFormat.CompressedSrgbAlphaS3tcDxt5Ext: case PixelInternalFormat.CompressedSignedRgRgtc2: case PixelInternalFormat.CompressedRgRgtc2: return (t.width * t.height); case PixelInternalFormat.Rgba: return t.data.Length; default: return t.data.Length; } } public unsafe Bitmap GLTextureToBitmap(RenderableTex t, int id) { Bitmap bitmap = new Bitmap(t.width, t.height); System.Drawing.Imaging.BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, t.width, t.height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); GL.BindTexture(TextureTarget.Texture2D, id); GL.GetTexImage(TextureTarget.Texture2D, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bitmapData.Scan0); bitmap.UnlockBits(bitmapData); return bitmap; } public override void OnClick(TreeView treeView) { UpdateEditor(); } public void UpdateEditor() { if (Viewport.Instance.gL_ControlModern1.Visible == false) PluginRuntime.FSHPDockState = WeifenLuo.WinFormsUI.Docking.DockState.Document; FTEXEditor docked = (FTEXEditor)LibraryGUI.Instance.GetContentDocked(new FTEXEditor()); if (docked == null) { docked = new FTEXEditor(); LibraryGUI.Instance.LoadDockContent(docked, PluginRuntime.FSHPDockState); } docked.Text = Text; docked.Dock = DockStyle.Fill; docked.LoadPicture(DisplayTexture()); docked.LoadProperty(this); } public class RenderableTex { public int width, height; public int display; public PixelInternalFormat pixelInternalFormat; public PixelFormat pixelFormat; public PixelType pixelType = PixelType.UnsignedByte; public int mipMapCount; public List> mipmaps = new List>(); public byte[] data; public class Surface { } } public Bitmap DisplayTexture(int DisplayMipIndex = 0, int ArrayIndex = 0) { if (renderedTex.mipmaps.Count <= 0) { throw new Exception("No texture data found"); } uint width = (uint)Math.Max(1, renderedTex.width >> DisplayMipIndex); uint height = (uint)Math.Max(1, renderedTex.height >> DisplayMipIndex); byte[] data = renderedTex.mipmaps[ArrayIndex][DisplayMipIndex]; return DecodeBlock(data, width, height, (GX2SurfaceFormat)format); } public static Bitmap DecodeBlock(byte[] data, uint Width, uint Height, GX2SurfaceFormat Format) { Bitmap decomp; try { if (Format == GX2SurfaceFormat.T_BC5_SNorm) return DDSCompressor.DecompressBC5(data, (int)Width, (int)Height, true); byte[] d = null; if (IsCompressedFormat(Format)) d = DDSCompressor.DecompressBlock(data, (int)Width, (int)Height, GetCompressedDXGI_FORMAT(Format)); else d = DDSCompressor.DecodePixelBlock(data, (int)Width, (int)Height, GetUncompressedDXGI_FORMAT(Format)); if (d != null) { decomp = BitmapExtension.GetBitmap(d, (int)Width, (int)Height); return SwapBlueRedChannels(decomp); } return BitmapExtension.GetBitmap(d, (int)Width, (int)Height);; } catch { throw new Exception($"Bad size from format {Format}"); } } public static byte[] CompressBlock(byte[] data, int width, int height, GTX.GX2SurfaceFormat format) { if (IsCompressedFormat((GX2SurfaceFormat)format)) return DDSCompressor.CompressBlock(data, width, height, GetCompressedDXGI_FORMAT((GX2SurfaceFormat)format)); else return DDSCompressor.EncodePixelBlock(data, width, height, GetUncompressedDXGI_FORMAT((GX2SurfaceFormat)format)); } private static DDS.DXGI_FORMAT GetUncompressedDXGI_FORMAT(GX2SurfaceFormat Format) { switch (Format) { case GX2SurfaceFormat.TC_R5_G5_B5_A1_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM; case GX2SurfaceFormat.TC_A1_B5_G5_R5_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM; case GX2SurfaceFormat.TC_R4_G4_B4_A4_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM; case GX2SurfaceFormat.TCS_R5_G6_B5_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G6R5_UNORM; case GX2SurfaceFormat.TCS_R8_G8_B8_A8_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM; case GX2SurfaceFormat.TCS_R8_G8_B8_A8_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM; case GX2SurfaceFormat.TCS_R10_G10_B10_A2_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_R10G10B10A2_UNORM; case GX2SurfaceFormat.TC_R11_G11_B10_Float: return DDS.DXGI_FORMAT.DXGI_FORMAT_R11G11B10_FLOAT; case GX2SurfaceFormat.TCD_R16_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_R16_UNORM; case GX2SurfaceFormat.TCD_R32_Float: return DDS.DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT; case GX2SurfaceFormat.T_R4_G4_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM; case GX2SurfaceFormat.TC_R8_G8_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8_UNORM; case GX2SurfaceFormat.TC_R8_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8_UNORM; case GX2SurfaceFormat.Invalid: throw new Exception("Invalid Format"); default: throw new Exception($"Cannot convert format {Format}"); } } private static bool IsCompressedFormat(GX2SurfaceFormat Format) { switch (Format) { case GX2SurfaceFormat.T_BC1_UNorm: case GX2SurfaceFormat.T_BC1_SRGB: case GX2SurfaceFormat.T_BC2_UNorm: case GX2SurfaceFormat.T_BC2_SRGB: case GX2SurfaceFormat.T_BC3_UNorm: case GX2SurfaceFormat.T_BC3_SRGB: case GX2SurfaceFormat.T_BC4_UNorm: case GX2SurfaceFormat.T_BC4_SNorm: case GX2SurfaceFormat.T_BC5_UNorm: case GX2SurfaceFormat.T_BC5_SNorm: return true; default: return false; } } private static DDS.DXGI_FORMAT GetCompressedDXGI_FORMAT(GX2SurfaceFormat Format) { switch (Format) { case GX2SurfaceFormat.T_BC1_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM; case GX2SurfaceFormat.T_BC1_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM; case GX2SurfaceFormat.T_BC2_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; case GX2SurfaceFormat.T_BC2_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; case GX2SurfaceFormat.T_BC3_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; case GX2SurfaceFormat.T_BC3_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; case GX2SurfaceFormat.T_BC4_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM; case GX2SurfaceFormat.T_BC4_SNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM; case GX2SurfaceFormat.T_BC5_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM; case GX2SurfaceFormat.T_BC5_SNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM; default: throw new Exception($"Cannot convert format {Format}"); } } public static Bitmap SwapBlueRedChannels(Bitmap bitmap) { return ColorComponentSelector(bitmap, GX2CompSel.ChannelB, GX2CompSel.ChannelG, GX2CompSel.ChannelR, GX2CompSel.ChannelA); } public Bitmap UpdateBitmap(Bitmap image) { return ColorComponentSelector(image, texture.CompSelR, texture.CompSelG, texture.CompSelB, texture.CompSelA); } public static Bitmap ColorComponentSelector(Bitmap image, GX2CompSel R, GX2CompSel G, GX2CompSel B, GX2CompSel A) { BitmapExtension.ColorSwapFilter color = new BitmapExtension.ColorSwapFilter(); if (R == GX2CompSel.ChannelR) color.CompRed = BitmapExtension.ColorSwapFilter.Red.Red; if (R == GX2CompSel.ChannelG) color.CompRed = BitmapExtension.ColorSwapFilter.Red.Green; if (R == GX2CompSel.ChannelB) color.CompRed = BitmapExtension.ColorSwapFilter.Red.Blue; if (R == GX2CompSel.ChannelA) color.CompRed = BitmapExtension.ColorSwapFilter.Red.Alpha; if (R == GX2CompSel.Always0) color.CompRed = BitmapExtension.ColorSwapFilter.Red.Zero; if (R == GX2CompSel.Always1) color.CompRed = BitmapExtension.ColorSwapFilter.Red.One; if (G == GX2CompSel.ChannelR) color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Red; if (G == GX2CompSel.ChannelG) color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Green; if (G == GX2CompSel.ChannelB) color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Blue; if (G == GX2CompSel.ChannelA) color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Alpha; if (G == GX2CompSel.Always0) color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Zero; if (G == GX2CompSel.Always1) color.CompGreen = BitmapExtension.ColorSwapFilter.Green.One; if (B == GX2CompSel.ChannelR) color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Red; if (B == GX2CompSel.ChannelG) color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Green; if (B == GX2CompSel.ChannelB) color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Blue; if (B == GX2CompSel.ChannelA) color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Alpha; if (B == GX2CompSel.Always0) color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Zero; if (B == GX2CompSel.Always1) color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.One; if (A == GX2CompSel.ChannelR) color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Red; if (A == GX2CompSel.ChannelG) color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Green; if (A == GX2CompSel.ChannelB) color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Blue; if (A == GX2CompSel.ChannelA) color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Alpha; if (A == GX2CompSel.Always0) color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Zero; if (A == GX2CompSel.Always1) color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.One; return BitmapExtension.SwapRGB(image, color); } } }