Switch-Toolbox/Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs

814 lines
34 KiB
C#
Raw Normal View History

2018-11-17 02:13:05 +00:00
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<string, FTEX> Textures = new Dictionary<string, FTEX>(); //To get instance of classes
public FTEXContainer()
{
Text = "Textures";
Name = "FTEX";
2018-11-17 02:13:05 +00:00
ContextMenu = new ContextMenu();
2018-12-02 20:01:51 +00:00
MenuItem importTex = new MenuItem("Import");
ContextMenu.MenuItems.Add(importTex);
importTex.Click += Import;
2018-11-17 02:13:05 +00:00
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 void RemoveTexture(FTEX textureData)
{
Nodes.Remove(textureData);
Textures.Remove(textureData.Text);
Viewport.Instance.UpdateViewport();
}
2018-12-02 20:01:51 +00:00
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<GTXImporterSettings> settings = new List<GTXImporterSettings>();
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;
}
2018-11-17 02:13:05 +00:00
2018-12-02 20:01:51 +00:00
return importer;
}
2018-11-17 02:13:05 +00:00
private void ExportAll(object sender, EventArgs args)
{
List<string> Formats = new List<string>();
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();
2018-12-02 20:01:51 +00:00
public Texture texture;
2018-11-17 02:13:05 +00:00
public FTEX()
{
ContextMenu = new ContextMenu();
MenuItem export = new MenuItem("Export");
ContextMenu.MenuItems.Add(export);
export.Click += Export;
2018-12-02 20:01:51 +00:00
MenuItem replace = new MenuItem("Replace");
ContextMenu.MenuItems.Add(replace);
replace.Click += Replace;
2018-11-17 02:13:05 +00:00
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)
{
2018-12-02 20:01:51 +00:00
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());
}
2018-11-17 02:13:05 +00:00
2018-12-02 20:01:51 +00:00
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 = surf.swizzle;
tex.Pitch = surf.pitch;
tex.Depth = surf.depth;
tex.MipCount = surf.numMips;
tex.MipOffsets = new uint[13];
for (int i = 0; i < 13; i++)
{
if (i < surf.mipOffset.Length)
tex.MipOffsets[i] = surf.mipOffset[i];
}
tex.Height = surf.height;
tex.Width = surf.width;
tex.Regs = new uint[5];
tex.ArrayLength = 1;
2018-12-02 20:01:51 +00:00
var channels = SetChannelsByFormat((GX2SurfaceFormat)surf.format);
tex.CompSelR = channels[0];
tex.CompSelG = channels[1];
tex.CompSelB = channels[2];
tex.CompSelA = channels[3];
tex.UserData = new ResDict<UserData>();
2018-12-02 20:01:51 +00:00
return tex;
2018-11-17 02:13:05 +00:00
}
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;
texture = tex;
2018-12-02 20:01:51 +00:00
renderedTex = new RenderableTex();
2018-11-17 02:13:05 +00:00
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;
2018-12-02 20:01:51 +00:00
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;
2018-12-02 20:01:51 +00:00
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;
2018-12-02 20:01:51 +00:00
surf.numMips = tex.MipCount;
surf.mipOffset = tex.MipOffsets;
surf.mipData = tex.MipData;
2018-12-02 20:01:51 +00:00
surf.tileMode = (uint)tex.TileMode;
surf.swizzle = tex.Swizzle;
List<byte[]> mips = GTX.Decode(surf);
renderedTex.mipmaps.Add(mips);
2018-12-02 20:01:51 +00:00
renderedTex.data = renderedTex.mipmaps[0][0];
LoadOpenGLTexture();
2018-12-02 20:01:51 +00:00
}
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;
2018-11-17 02:13:05 +00:00
}
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);
2018-11-17 02:13:05 +00:00
}
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;
2018-11-28 18:22:25 +00:00
dds.header.pitchOrLinearSize = (uint)renderedTex.mipmaps[0][0].Length;
2018-11-17 02:13:05 +00:00
2018-11-28 18:22:25 +00:00
if (IsCompressedFormat((GX2SurfaceFormat)format))
dds.SetFlags(GetCompressedDXGI_FORMAT((GX2SurfaceFormat)format));
else
dds.SetFlags(GetUncompressedDXGI_FORMAT((GX2SurfaceFormat)format));
2018-11-17 02:13:05 +00:00
2018-11-28 18:22:25 +00:00
dds.Save(dds, FileName, renderedTex.mipmaps);
2018-11-17 02:13:05 +00:00
}
public void LoadOpenGLTexture()
{
if (OpenTKSharedResources.SetupStatus == OpenTKSharedResources.SharedResourceStatus.Unitialized)
return;
2018-12-02 20:01:51 +00:00
2018-11-17 02:13:05 +00:00
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
2018-12-02 20:01:51 +00:00
renderedTex.data = DDSCompressor.DecompressBC5(renderedTex.mipmaps[0][0], (int)renderedTex.width, (int)renderedTex.height, true, true);
2018-11-17 02:13:05 +00:00
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;
2018-11-22 18:08:50 +00:00
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;
2018-11-17 02:13:05 +00:00
}
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<byte>(TextureTarget.Texture2D, 0, (InternalFormat)t.pixelInternalFormat,
t.width, t.height, 0, getImageSize(t), t.data);
//Debug.WriteLine(GL.GetError());
}
else
{
GL.TexImage2D<byte>(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)
{
2018-12-02 20:01:51 +00:00
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);
2018-11-17 02:13:05 +00:00
}
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<List<byte[]>> mipmaps = new List<List<byte[]>>();
2018-12-02 20:01:51 +00:00
public byte[] data;
2018-11-17 02:13:05 +00:00
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);
2018-11-17 02:13:05 +00:00
}
public static Bitmap DecodeBlock(byte[] data, uint Width, uint Height, GX2SurfaceFormat Format)
2018-11-17 02:13:05 +00:00
{
Bitmap decomp;
2018-11-22 18:08:50 +00:00
try
{
if (Format == GX2SurfaceFormat.T_BC5_SNorm)
return DDSCompressor.DecompressBC5(data, (int)Width, (int)Height, true);
2018-11-22 18:08:50 +00:00
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));
2018-11-22 18:08:50 +00:00
if (d != null)
{
decomp = BitmapExtension.GetBitmap(d, (int)Width, (int)Height);
return SwapBlueRedChannels(decomp);
}
return BitmapExtension.GetBitmap(d, (int)Width, (int)Height);;
}
catch
{
2018-11-22 18:08:50 +00:00
throw new Exception($"Bad size from format {Format}");
}
2018-12-02 20:01:51 +00:00
}
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)
{
2018-11-17 02:13:05 +00:00
switch (Format)
{
2018-12-02 20:01:51 +00:00
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;
2018-12-02 20:01:51 +00:00
case GX2SurfaceFormat.TCS_R8_G8_B8_A8_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM;
2018-11-22 18:08:50 +00:00
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");
2018-11-17 02:13:05 +00:00
default:
throw new Exception($"Cannot convert format {Format}");
2018-11-17 02:13:05 +00:00
}
}
private static bool IsCompressedFormat(GX2SurfaceFormat Format)
{
switch (Format)
{
case GX2SurfaceFormat.T_BC1_UNorm:
case GX2SurfaceFormat.T_BC1_SRGB:
case GX2SurfaceFormat.T_BC2_UNorm:
2018-11-22 18:08:50 +00:00
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;
2018-12-02 20:01:51 +00:00
case GX2SurfaceFormat.T_BC1_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM;
2018-11-22 18:08:50 +00:00
case GX2SurfaceFormat.T_BC2_UNorm: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM;
2018-12-02 20:01:51 +00:00
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;
2018-12-02 20:01:51 +00:00
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);
}
2018-11-17 02:13:05 +00:00
public Bitmap UpdateBitmap(Bitmap image)
{
2018-12-02 20:01:51 +00:00
return ColorComponentSelector(image, texture.CompSelR,
texture.CompSelG, texture.CompSelB, texture.CompSelA);
2018-11-17 02:13:05 +00:00
}
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;
2018-11-17 02:13:05 +00:00
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;
2018-11-17 02:13:05 +00:00
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;
2018-11-17 02:13:05 +00:00
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;
2018-11-17 02:13:05 +00:00
return BitmapExtension.SwapRGB(image, color);
}
}
}