1438 lines
57 KiB
C#
1438 lines
57 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using System.ComponentModel;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Syroot.NintenTools.NSW.Bntx;
|
|
using Syroot.NintenTools.NSW.Bntx.GFX;
|
|
using System.Runtime.InteropServices;
|
|
using OpenTK;
|
|
using OpenTK.Graphics.OpenGL;
|
|
using Switch_Toolbox.Library;
|
|
using WeifenLuo.WinFormsUI.Docking;
|
|
using Smash_Forge.Rendering;
|
|
using Switch_Toolbox.Library.Forms;
|
|
using Switch_Toolbox.Library.IO;
|
|
|
|
namespace FirstPlugin
|
|
{
|
|
public class Formats
|
|
{
|
|
public enum BNTXImageFormat
|
|
{
|
|
IMAGE_FORMAT_INVALID = 0x0,
|
|
IMAGE_FORMAT_R8_G8_B8_A8 = 0x0b,
|
|
IMAGE_FORMAT_R5_G6_B5 = 0x07,
|
|
IMAGE_FORMAT_R8 = 0x02,
|
|
IMAGE_FORMAT_R8_G8 = 0x09,
|
|
IMAGE_FORMAT_BC1 = 0x1a,
|
|
IMAGE_FORMAT_BC2 = 0x1b,
|
|
IMAGE_FORMAT_BC3 = 0x1c,
|
|
IMAGE_FORMAT_BC4 = 0x1d,
|
|
IMAGE_FORMAT_BC5 = 0x1e,
|
|
IMAGE_FORMAT_BC6 = 0x1f,
|
|
IMAGE_FORMAT_BC7 = 0x20,
|
|
};
|
|
|
|
public enum BNTXImageTypes
|
|
{
|
|
UNORM = 0x01,
|
|
SNORM = 0x02,
|
|
SRGB = 0x06,
|
|
};
|
|
|
|
public static uint blk_dims(uint format)
|
|
{
|
|
switch (format)
|
|
{
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC1:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC2:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC3:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC4:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC5:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC6:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC7:
|
|
case 0x2d:
|
|
return 0x44;
|
|
|
|
case 0x2e: return 0x54;
|
|
case 0x2f: return 0x55;
|
|
case 0x30: return 0x65;
|
|
case 0x31: return 0x66;
|
|
case 0x32: return 0x85;
|
|
case 0x33: return 0x86;
|
|
case 0x34: return 0x88;
|
|
case 0x35: return 0xa5;
|
|
case 0x36: return 0xa6;
|
|
case 0x37: return 0xa8;
|
|
case 0x38: return 0xaa;
|
|
case 0x39: return 0xca;
|
|
case 0x3a: return 0xcc;
|
|
|
|
default: return 0x11;
|
|
}
|
|
}
|
|
|
|
public static uint bpps(uint format)
|
|
{
|
|
switch (format)
|
|
{
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_R8_G8_B8_A8: return 4;
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_R8: return 1;
|
|
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_R5_G6_B5:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_R8_G8:
|
|
return 2;
|
|
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC1:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC4:
|
|
return 8;
|
|
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC2:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC3:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC5:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC6:
|
|
case (uint)BNTXImageFormat.IMAGE_FORMAT_BC7:
|
|
case 0x2e:
|
|
case 0x2f:
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3a:
|
|
return 16;
|
|
default: return 0x00;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class BNTX : IFileFormat
|
|
{
|
|
public bool CanSave { get; set; } = false;
|
|
public bool FileIsEdited { get; set; } = false;
|
|
public bool FileIsCompressed { get; set; } = false;
|
|
public string[] Description { get; set; } = new string[] { "*BNTX"};
|
|
public string[] Extension { get; set; } = new string[] { "*.bntx"};
|
|
public string Magic { get; set; } = "BNTX";
|
|
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
|
public byte[] Data { get; set; }
|
|
public string FileName { get; set; }
|
|
public TreeNodeFile EditorRoot { get; set; }
|
|
public bool IsActive { get; set; } = false;
|
|
public bool UseEditMenu { get; set; } = false;
|
|
public int Alignment { get; set; } = 0;
|
|
public string FilePath { get; set; }
|
|
public IFileInfo IFileInfo { get; set; }
|
|
public Type[] Types
|
|
{
|
|
get
|
|
{
|
|
List<Type> types = new List<Type>();
|
|
types.Add(typeof(MenuExt));
|
|
return types.ToArray();
|
|
}
|
|
}
|
|
class MenuExt : IFileMenuExtension
|
|
{
|
|
public ToolStripItemDark[] NewFileMenuExtensions => null;
|
|
public ToolStripItemDark[] ToolsMenuExtensions => newFileExt;
|
|
public ToolStripItemDark[] TitleBarExtensions => null;
|
|
public ToolStripItemDark[] CompressionMenuExtensions => null;
|
|
public ToolStripItemDark[] ExperimentalMenuExtensions => null;
|
|
|
|
ToolStripItemDark[] newFileExt = new ToolStripItemDark[1];
|
|
public MenuExt()
|
|
{
|
|
newFileExt[0] = new ToolStripItemDark("Extract BNTX");
|
|
newFileExt[0].Click += Export;
|
|
}
|
|
private void Export(object sender, EventArgs args)
|
|
{
|
|
OpenFileDialog ofd = new OpenFileDialog();
|
|
ofd.Multiselect = true;
|
|
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
foreach (string file in ofd.FileNames)
|
|
{
|
|
FileReader reader = new FileReader(ofd.FileName);
|
|
reader.Seek(16, SeekOrigin.Begin);
|
|
int offsetName = reader.ReadInt32();
|
|
|
|
reader.Seek(offsetName, SeekOrigin.Begin);
|
|
string Name = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated);
|
|
|
|
Console.WriteLine(file + " " + Name);
|
|
|
|
reader.Close();
|
|
reader.Dispose();
|
|
|
|
// System.IO.File.Move(file, Name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
byte[] ByteBuffer = File.ReadAllBytes(ofd.FileName);
|
|
byte[] StringBytes = Encoding.UTF8.GetBytes("BNTX");
|
|
try
|
|
{
|
|
while (true)
|
|
{
|
|
byte byt = reader.ReadByte();
|
|
|
|
if (byt == 0x42)
|
|
{
|
|
reader.Seek(-1, SeekOrigin.Current);
|
|
int TryRdMagic = reader.ReadInt32();
|
|
if (TryRdMagic == 0x424E5458)
|
|
{
|
|
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
|
|
|
|
long BNTXpos = reader.Position - 4;
|
|
Console.WriteLine("String was found at offset {0}", reader.Position);
|
|
|
|
reader.Seek(BNTXpos + 16, SeekOrigin.Begin);
|
|
int offsetName = reader.ReadInt32();
|
|
|
|
reader.Seek(BNTXpos + offsetName, SeekOrigin.Begin);
|
|
string Name = reader.ReadString();
|
|
|
|
reader.Seek(BNTXpos + 28, SeekOrigin.Begin);
|
|
int size = reader.ReadInt32();
|
|
|
|
reader.Seek(BNTXpos, SeekOrigin.Begin);
|
|
|
|
File.WriteAllBytes(Name + ".bntx", reader.ReadBytes(size));
|
|
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
catch
|
|
{
|
|
|
|
}
|
|
}
|
|
}*/
|
|
|
|
BinaryTextureContainer bntx;
|
|
|
|
public void Load()
|
|
{
|
|
IFileInfo = new IFileInfo();
|
|
|
|
IsActive = true;
|
|
UseEditMenu = true;
|
|
CanSave = true;
|
|
bntx = new BinaryTextureContainer(Data, FileName, "", this);
|
|
EditorRoot = bntx;
|
|
}
|
|
public void Unload()
|
|
{
|
|
foreach (TextureData tex in bntx.Textures.Values)
|
|
{
|
|
tex.mipmaps.Clear();
|
|
tex.renderedGLTex = null;
|
|
}
|
|
|
|
bntx.Textures.Clear();
|
|
bntx.Nodes.Clear();
|
|
}
|
|
public byte[] Save()
|
|
{
|
|
return bntx.Save();
|
|
}
|
|
}
|
|
|
|
public class BinaryTextureContainer : TreeNodeFile
|
|
{
|
|
public Dictionary<string, TextureData> Textures;
|
|
|
|
public byte[] Data;
|
|
public PropertieGridData prop;
|
|
public BntxFile BinaryTexFile;
|
|
public string FileNameText;
|
|
|
|
MenuItem save = new MenuItem("Save");
|
|
MenuItem replace = new MenuItem("Replace");
|
|
MenuItem rename = new MenuItem("Rename");
|
|
MenuItem importTex = new MenuItem("Import Texture");
|
|
MenuItem exportAll = new MenuItem("Export All Textures");
|
|
MenuItem clear = new MenuItem("Clear");
|
|
|
|
private bool hasParent;
|
|
public bool HasParent
|
|
{
|
|
get
|
|
{
|
|
hasParent = Parent != null;
|
|
replace.Enabled = hasParent;
|
|
rename.Enabled = hasParent;
|
|
return hasParent;
|
|
}
|
|
}
|
|
public bool CanReplace;
|
|
public bool AllGLInitialized
|
|
{
|
|
get
|
|
{
|
|
if (Textures.Any(item => item.Value.GLInitialized == false))
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public BinaryTextureContainer()
|
|
{
|
|
ImageKey = "bntx";
|
|
SelectedImageKey = "bntx";
|
|
}
|
|
public BinaryTextureContainer(byte[] data, string Name = "", string FileName = "", IFileFormat handler = null)
|
|
{
|
|
if (data.Length == 0)
|
|
data = CreateNewBNTX(Name);
|
|
|
|
ImageKey = "bntx";
|
|
SelectedImageKey = "bntx";
|
|
|
|
FileNameText = FileName;
|
|
LoadFile(data, Name);
|
|
|
|
PluginRuntime.bntxContainers.Add(this);
|
|
FileHandler = handler;
|
|
|
|
//Check if bntx is parented to determine if an archive is used
|
|
bool checkParent = HasParent;
|
|
|
|
ContextMenu = new ContextMenu();
|
|
ContextMenu.MenuItems.Add(save);
|
|
ContextMenu.MenuItems.Add(replace);
|
|
ContextMenu.MenuItems.Add(rename);
|
|
ContextMenu.MenuItems.Add(importTex);
|
|
ContextMenu.MenuItems.Add(exportAll);
|
|
ContextMenu.MenuItems.Add(clear);
|
|
|
|
save.Click += Save;
|
|
replace.Click += Import;
|
|
rename.Click += Rename;
|
|
importTex.Click += ImportTexture;
|
|
exportAll.Click += ExportAll;
|
|
clear.Click += Clear;
|
|
}
|
|
private byte[] CreateNewBNTX(string Name)
|
|
{
|
|
MemoryStream mem = new MemoryStream();
|
|
|
|
BntxFile bntx = new BntxFile();
|
|
bntx.Target = new char[] { 'N', 'X', ' ', ' '};
|
|
bntx.Name = Name;
|
|
bntx.Alignment = 0xC;
|
|
bntx.TargetAddressSize = 0x40;
|
|
bntx.VersionMajor = 0;
|
|
bntx.VersionMajor2 = 4;
|
|
bntx.VersionMinor = 0;
|
|
bntx.VersionMinor2 = 0;
|
|
bntx.Textures = new List<Texture>();
|
|
bntx.TextureDict = new ResDict();
|
|
bntx.RelocationTable = new RelocationTable();
|
|
bntx.Flag = 0;
|
|
bntx.Save(mem);
|
|
|
|
return mem.ToArray();
|
|
}
|
|
public void RemoveTexture(TextureData textureData)
|
|
{
|
|
Nodes.Remove(textureData);
|
|
Textures.Remove(textureData.Text);
|
|
Viewport.Instance.UpdateViewport();
|
|
}
|
|
public override void OnClick(TreeView treeView)
|
|
{
|
|
|
|
}
|
|
//Check right click to enable/disable certain context menus
|
|
public override void OnMouseRightClick(TreeView treeview)
|
|
{
|
|
bool checkParent = HasParent;
|
|
}
|
|
|
|
public void LoadFile(byte[] data, string Name = "")
|
|
{
|
|
Textures = new Dictionary<string, TextureData>();
|
|
|
|
Data = data;
|
|
BinaryTexFile = new BntxFile(new MemoryStream(Data));
|
|
Text = BinaryTexFile.Name;
|
|
|
|
prop = new PropertieGridData();
|
|
prop.Target = new string(BinaryTexFile.Target);
|
|
prop.VersionMajor = BinaryTexFile.VersionMajor;
|
|
prop.VersionMajor2 = BinaryTexFile.VersionMajor2;
|
|
prop.VersionMinor = BinaryTexFile.VersionMinor;
|
|
prop.VersionMinor2 = BinaryTexFile.VersionMinor2;
|
|
prop.VersionFull = $"{BinaryTexFile.VersionMajor}.{BinaryTexFile.VersionMajor2}.{BinaryTexFile.VersionMinor}.{BinaryTexFile.VersionMinor2}";
|
|
|
|
foreach (Texture tex in BinaryTexFile.Textures)
|
|
{
|
|
TextureData texData = new TextureData(tex, BinaryTexFile);
|
|
// texData.LoadOpenGLTexture();
|
|
|
|
Nodes.Add(texData);
|
|
Textures.Add(tex.Name, texData);
|
|
}
|
|
BinaryTexFile.Textures.Clear(); //We don't need these in memeory anymore
|
|
BinaryTexFile.TextureDict.Clear();
|
|
}
|
|
private void ImportTexture(object sender, EventArgs args)
|
|
{
|
|
ImportTexture();
|
|
}
|
|
public void ImportTexture()
|
|
{
|
|
OpenFileDialog ofd = new OpenFileDialog();
|
|
ofd.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(*.*)|*.*";
|
|
|
|
ofd.DefaultExt = "bftex";
|
|
ofd.Multiselect = true;
|
|
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
BinaryTextureImporterList importer = new BinaryTextureImporterList();
|
|
|
|
List<TextureImporterSettings> settings = new List<TextureImporterSettings>();
|
|
foreach (string name in ofd.FileNames)
|
|
{
|
|
string ext = Path.GetExtension(name);
|
|
ext = ext.ToLower();
|
|
|
|
if (ext == ".dds" || ext == ".bftex")
|
|
{
|
|
AddTexture(name);
|
|
}
|
|
else
|
|
{
|
|
settings.Add(LoadSettings(name));
|
|
|
|
if (settings.Count == 0)
|
|
{
|
|
importer.Dispose();
|
|
return;
|
|
}
|
|
|
|
importer.LoadSettings(settings, this);
|
|
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)
|
|
{
|
|
Texture tex = setting.FromBitMap(setting.DataBlockOutput[0], setting);
|
|
if (setting.textureData != null)
|
|
{
|
|
setting.textureData.LoadTexture(tex, 1);
|
|
}
|
|
else
|
|
{
|
|
setting.textureData = new TextureData(tex, setting.bntx);
|
|
}
|
|
|
|
int i = 0;
|
|
if (Textures.ContainsKey(setting.textureData.Text))
|
|
{
|
|
setting.textureData.Text = setting.textureData.Text + i++;
|
|
}
|
|
|
|
Nodes.Add(setting.textureData);
|
|
Textures.Add(setting.textureData.Text, setting.textureData);
|
|
setting.textureData.LoadOpenGLTexture();
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("Something went wrong???");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
settings.Clear();
|
|
GC.Collect();
|
|
Cursor.Current = Cursors.Default;
|
|
}
|
|
}
|
|
//This function is an optional feature that will import a dummy texture if one is missing in the materials
|
|
public void ImportPlaceholderTexture(string TextureName)
|
|
{
|
|
if (Textures.ContainsKey(TextureName))
|
|
return;
|
|
|
|
if (TextureName == "Basic_Alb")
|
|
ImportBasicTextures("Basic_Alb");
|
|
else if (TextureName == "Basic_Nrm")
|
|
ImportBasicTextures("Basic_Nrm");
|
|
else if (TextureName == "Basic_Spm")
|
|
ImportBasicTextures("Basic_Spm");
|
|
else if (TextureName == "Basic_Sphere")
|
|
ImportBasicTextures("Basic_Sphere");
|
|
else if (TextureName == "Basic_Mtl")
|
|
ImportBasicTextures("Basic_Mtl");
|
|
else if (TextureName == "Basic_Rgh")
|
|
ImportBasicTextures("Basic_Rgh");
|
|
else if (TextureName == "Basic_MRA")
|
|
ImportBasicTextures("Basic_MRA");
|
|
else if (TextureName == "Basic_Bake_st0")
|
|
ImportBasicTextures("Basic_Bake_st0");
|
|
else if (TextureName == "Basic_Bake_st1")
|
|
ImportBasicTextures("Basic_Bake_st1");
|
|
else if (TextureName == "Basic_Emm")
|
|
ImportBasicTextures("Basic_Emm");
|
|
else
|
|
{
|
|
ImportPlaceholderTexture(Properties.Resources.InjectTexErrored, TextureName);
|
|
}
|
|
}
|
|
private void ImportPlaceholderTexture(byte[] data, string TextureName)
|
|
{
|
|
TextureImporterSettings importDDS = new TextureImporterSettings();
|
|
importDDS.LoadDDS(TextureName, BinaryTexFile, data);
|
|
|
|
TextureData texData = importDDS.textureData;
|
|
texData.Text = TextureName;
|
|
|
|
Nodes.Add(texData);
|
|
Textures.Add(TextureName, texData);
|
|
texData.LoadOpenGLTexture();
|
|
}
|
|
public void ImportBasicTextures(string TextureName, bool BC5Nrm = true)
|
|
{
|
|
if (Textures.ContainsKey(TextureName))
|
|
return;
|
|
|
|
if (TextureName == "Basic_Alb")
|
|
ImportPlaceholderTexture(Properties.Resources.InjectTexErrored, TextureName);
|
|
if (TextureName == "Basic_Nrm" && BC5Nrm)
|
|
ImportPlaceholderTexture(Properties.Resources.Basic_NrmBC5, TextureName);
|
|
if (TextureName == "Basic_Nrm" && BC5Nrm == false)
|
|
ImportPlaceholderTexture(Properties.Resources.Basic_Nrm, TextureName);
|
|
if (TextureName == "Basic_Spm")
|
|
ImportPlaceholderTexture(Properties.Resources.Black, TextureName);
|
|
if (TextureName == "Basic_Sphere")
|
|
ImportPlaceholderTexture(Properties.Resources.Black, TextureName);
|
|
if (TextureName == "Basic_Mtl")
|
|
ImportPlaceholderTexture(Properties.Resources.Black, TextureName);
|
|
if (TextureName == "Basic_Rgh")
|
|
ImportPlaceholderTexture(Properties.Resources.White, TextureName);
|
|
if (TextureName == "Basic_MRA")
|
|
ImportPlaceholderTexture(Properties.Resources.Black, TextureName);
|
|
if (TextureName == "Basic_Bake_st0")
|
|
ImportPlaceholderTexture(Properties.Resources.Basic_Bake_st0, TextureName);
|
|
if (TextureName == "Basic_Bake_st1")
|
|
ImportPlaceholderTexture(Properties.Resources.Basic_Bake_st1, TextureName);
|
|
}
|
|
public TextureImporterSettings LoadSettings(string name)
|
|
{
|
|
var importer = new TextureImporterSettings();
|
|
|
|
string ext = Path.GetExtension(name);
|
|
ext = ext.ToLower();
|
|
|
|
switch (ext)
|
|
{
|
|
case ".bftex":
|
|
Texture tex = new Texture();
|
|
tex.Import(name);
|
|
break;
|
|
case ".dds":
|
|
importer.LoadDDS(name, BinaryTexFile);
|
|
break;
|
|
default:
|
|
importer.LoadBitMap(name, BinaryTexFile);
|
|
break;
|
|
}
|
|
|
|
return importer;
|
|
}
|
|
public TextureData AddTexture(string name)
|
|
{
|
|
var importer = new TextureImporterSettings();
|
|
|
|
TextureData texData = null;
|
|
string ext = Path.GetExtension(name);
|
|
ext = ext.ToLower();
|
|
|
|
switch (ext)
|
|
{
|
|
case ".bftex":
|
|
Texture tex = new Texture();
|
|
tex.Import(name);
|
|
texData = new TextureData(tex, BinaryTexFile);
|
|
break;
|
|
case ".dds":
|
|
importer.LoadDDS(name, BinaryTexFile);
|
|
texData = importer.textureData;
|
|
break;
|
|
default:
|
|
importer.LoadBitMap(name, BinaryTexFile);
|
|
texData = importer.textureData;
|
|
break;
|
|
}
|
|
if (texData != null)
|
|
{
|
|
List<string> keyList = new List<string>(Textures.Keys);
|
|
texData.Text = Utils.RenameDuplicateString(keyList, texData.Text);
|
|
|
|
Nodes.Add(texData);
|
|
Textures.Add(texData.Text, texData);
|
|
texData.LoadOpenGLTexture();
|
|
}
|
|
return texData;
|
|
}
|
|
private void Clear(object sender, EventArgs args)
|
|
{
|
|
Nodes.Clear();
|
|
Textures.Clear();
|
|
GC.Collect();
|
|
}
|
|
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 (TextureData 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 byte[] Save()
|
|
{
|
|
BinaryTexFile.Textures.Clear();
|
|
BinaryTexFile.TextureDict.Clear();
|
|
|
|
foreach (TextureData tex in Textures.Values)
|
|
{
|
|
tex.Texture.Name = tex.Text;
|
|
|
|
BinaryTexFile.Textures.Add(tex.Texture);
|
|
BinaryTexFile.TextureDict.Add(tex.Text);
|
|
}
|
|
|
|
MemoryStream mem = new MemoryStream();
|
|
BinaryTexFile.Save(mem);
|
|
|
|
return mem.ToArray();
|
|
}
|
|
|
|
public class PropertieGridData
|
|
{
|
|
[Browsable(true)]
|
|
[Category("BNTX")]
|
|
[DisplayName("Name")]
|
|
public string Name { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[Category("BNTX")]
|
|
[DisplayName("Original Path")]
|
|
public string Path { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[Category("BNTX")]
|
|
[DisplayName("Target")]
|
|
public string Target { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[ReadOnly(true)]
|
|
[Category("Versions")]
|
|
[DisplayName("Full Version")]
|
|
public string VersionFull { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[Category("Versions")]
|
|
[DisplayName("Version Major 1")]
|
|
public uint VersionMajor { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[Category("Versions")]
|
|
[DisplayName("Version Major 2")]
|
|
public uint VersionMajor2 { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[Category("Versions")]
|
|
[DisplayName("Version Minor 1")]
|
|
public uint VersionMinor { get; set; }
|
|
|
|
[Browsable(true)]
|
|
[Category("Versions")]
|
|
[DisplayName("Version Minor 2")]
|
|
public uint VersionMinor2 { get; set; }
|
|
}
|
|
|
|
private void Import(object sender, EventArgs args)
|
|
{
|
|
OpenFileDialog ofd = new OpenFileDialog();
|
|
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
Data = File.ReadAllBytes(ofd.FileName);
|
|
LoadFile(Data);
|
|
}
|
|
}
|
|
private void Rename(object sender, EventArgs args)
|
|
{
|
|
RenameDialog dialog = new RenameDialog();
|
|
dialog.SetString(Text);
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
Text = dialog.textBox1.Text;
|
|
}
|
|
}
|
|
private void Save(object sender, EventArgs args)
|
|
{
|
|
SaveFileDialog sfd = new SaveFileDialog();
|
|
sfd.DefaultExt = "bntx";
|
|
sfd.Filter = "Supported Formats|*.bntx;";
|
|
sfd.FileName = FileHandler.FileName;
|
|
|
|
if (sfd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
File.WriteAllBytes(sfd.FileName, FileHandler.Save());
|
|
}
|
|
}
|
|
}
|
|
|
|
public class TextureData : TreeNodeCustom
|
|
{
|
|
public Texture Texture;
|
|
public BntxFile bntxFile;
|
|
public List<List<byte[]>> mipmaps = new List<List<byte[]>>();
|
|
public BRTI_Texture renderedGLTex = new BRTI_Texture();
|
|
public bool GLInitialized = false;
|
|
|
|
public TextureData()
|
|
{
|
|
ImageKey = "Texture";
|
|
SelectedImageKey = "Texture";
|
|
}
|
|
public TextureData(Texture tex, BntxFile bntx)
|
|
{
|
|
ImageKey = "Texture";
|
|
SelectedImageKey = "Texture";
|
|
|
|
Texture = tex;
|
|
bntxFile = bntx;
|
|
|
|
Text = tex.Name;
|
|
|
|
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;
|
|
|
|
string TargetString = new string(bntx.Target);
|
|
|
|
int target = 0;
|
|
if (TargetString == "NX ")
|
|
target = 1;
|
|
}
|
|
public override void OnClick(TreeView treeView)
|
|
{
|
|
UpdateBNTXEditor();
|
|
}
|
|
public void UpdateBNTXEditor()
|
|
{
|
|
if (Viewport.Instance.gL_ControlModern1.Visible == false)
|
|
PluginRuntime.FSHPDockState = WeifenLuo.WinFormsUI.Docking.DockState.Document;
|
|
|
|
BNTXEditor docked = (BNTXEditor)LibraryGUI.Instance.GetContentDocked(new BNTXEditor());
|
|
if (docked == null)
|
|
{
|
|
docked = new BNTXEditor();
|
|
LibraryGUI.Instance.LoadDockContent(docked, PluginRuntime.FSHPDockState);
|
|
}
|
|
docked.Text = Text;
|
|
docked.Dock = DockStyle.Fill;
|
|
docked.LoadProperty(this);
|
|
}
|
|
public BRTI_Texture LoadOpenGLTexture()
|
|
{
|
|
if (OpenTKSharedResources.SetupStatus == OpenTKSharedResources.SharedResourceStatus.Unitialized)
|
|
return null;
|
|
|
|
LoadTexture(Texture);
|
|
|
|
if (mipmaps.Count <= 0)
|
|
{
|
|
throw new Exception("No texture data found");
|
|
}
|
|
|
|
renderedGLTex.data = mipmaps[0][0];
|
|
renderedGLTex.width = (int)Texture.Width;
|
|
renderedGLTex.height = (int)Texture.Height;
|
|
|
|
switch (Texture.Format)
|
|
{
|
|
case SurfaceFormat.BC1_UNORM:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext;
|
|
break;
|
|
case SurfaceFormat.BC1_SRGB:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext;
|
|
break;
|
|
case SurfaceFormat.BC2_UNORM:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext;
|
|
break;
|
|
case SurfaceFormat.BC2_SRGB:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt3Ext;
|
|
break;
|
|
case SurfaceFormat.BC3_UNORM:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext;
|
|
break;
|
|
case SurfaceFormat.BC3_SRGB:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt5Ext;
|
|
break;
|
|
case SurfaceFormat.BC4_UNORM:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRedRgtc1;
|
|
break;
|
|
case SurfaceFormat.BC4_SNORM:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedSignedRedRgtc1;
|
|
break;
|
|
case SurfaceFormat.BC5_UNORM:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgRgtc2;
|
|
break;
|
|
case SurfaceFormat.BC5_SNORM:
|
|
renderedGLTex.data = DDSCompressor.DecompressBC5(mipmaps[0][0], (int)Texture.Width, (int)Texture.Height, true, true);
|
|
renderedGLTex.type = PixelInternalFormat.Rgba;
|
|
renderedGLTex.utype = OpenTK.Graphics.OpenGL.PixelFormat.Rgba;
|
|
break;
|
|
case SurfaceFormat.BC6_FLOAT:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgbBptcSignedFloat;
|
|
break;
|
|
case SurfaceFormat.BC6_UFLOAT:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgbBptcUnsignedFloat;
|
|
break;
|
|
case SurfaceFormat.BC7_SRGB:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedSrgbAlphaBptcUnorm;
|
|
break;
|
|
case SurfaceFormat.BC7_UNORM:
|
|
renderedGLTex.type = PixelInternalFormat.CompressedRgbaBptcUnorm;
|
|
break;
|
|
case SurfaceFormat.R8_G8_B8_A8_SRGB:
|
|
renderedGLTex.type = PixelInternalFormat.Rgba;
|
|
renderedGLTex.utype = OpenTK.Graphics.OpenGL.PixelFormat.Rgba;
|
|
break;
|
|
}
|
|
renderedGLTex.display = loadImage(renderedGLTex);
|
|
GLInitialized = true;
|
|
|
|
return renderedGLTex;
|
|
}
|
|
|
|
//Gets the decompressed byte[]
|
|
public static Bitmap DecodeBlock(byte[] data, uint Width, uint Height, SurfaceFormat Format)
|
|
{
|
|
Bitmap decomp;
|
|
|
|
if (Format == SurfaceFormat.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 if (IsAtscFormat(Format))
|
|
d = null;
|
|
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 null;
|
|
}
|
|
private static DDS.DXGI_FORMAT GetUncompressedDXGI_FORMAT(SurfaceFormat Format)
|
|
{
|
|
switch (Format)
|
|
{
|
|
case SurfaceFormat.A1_B5_G5_R5_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM;
|
|
case SurfaceFormat.A4_B4_G4_R4_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM;
|
|
case SurfaceFormat.B5_G5_R5_A1_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM;
|
|
case SurfaceFormat.B5_G6_R5_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G6R5_UNORM;
|
|
case SurfaceFormat.B8_G8_R8_A8_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
|
|
case SurfaceFormat.B8_G8_R8_A8_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
case SurfaceFormat.R10_G10_B10_A2_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_R10G10B10A2_UNORM;
|
|
case SurfaceFormat.R11_G11_B10_FLOAT: return DDS.DXGI_FORMAT.DXGI_FORMAT_R11G11B10_FLOAT;
|
|
case SurfaceFormat.R16_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_R16_UNORM;
|
|
case SurfaceFormat.R32_FLOAT: return DDS.DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT;
|
|
case SurfaceFormat.R4_G4_B4_A4_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM;
|
|
case SurfaceFormat.R4_G4_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM;
|
|
case SurfaceFormat.R5_G5_B5_A1_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM;
|
|
case SurfaceFormat.R5_G6_B5_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_B5G6R5_UNORM;
|
|
case SurfaceFormat.R8_G8_B8_A8_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
|
case SurfaceFormat.R8_G8_B8_A8_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
case SurfaceFormat.R8_G8_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8_UNORM;
|
|
case SurfaceFormat.R8_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_R8_UNORM;
|
|
case SurfaceFormat.Invalid: throw new Exception("Invalid Format");
|
|
default:
|
|
throw new Exception($"Cannot convert format {Format}");
|
|
}
|
|
}
|
|
private static DDS.DXGI_FORMAT GetCompressedDXGI_FORMAT(SurfaceFormat Format)
|
|
{
|
|
switch (Format)
|
|
{
|
|
case SurfaceFormat.BC1_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM;
|
|
case SurfaceFormat.BC1_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM_SRGB;
|
|
case SurfaceFormat.BC2_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM;
|
|
case SurfaceFormat.BC2_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM_SRGB;
|
|
case SurfaceFormat.BC3_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM;
|
|
case SurfaceFormat.BC3_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM_SRGB;
|
|
case SurfaceFormat.BC4_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM;
|
|
case SurfaceFormat.BC4_SNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM;
|
|
case SurfaceFormat.BC5_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM;
|
|
case SurfaceFormat.BC5_SNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM;
|
|
case SurfaceFormat.BC6_UFLOAT: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC6H_UF16;
|
|
case SurfaceFormat.BC6_FLOAT: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC6H_SF16;
|
|
case SurfaceFormat.BC7_UNORM: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM;
|
|
case SurfaceFormat.BC7_SRGB: return DDS.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB;
|
|
case SurfaceFormat.Invalid: throw new Exception("Invalid Format");
|
|
default:
|
|
throw new Exception($"Cannot convert format {Format}");
|
|
}
|
|
}
|
|
private static bool IsCompressedFormat(SurfaceFormat Format)
|
|
{
|
|
switch (Format)
|
|
{
|
|
case SurfaceFormat.BC1_UNORM:
|
|
case SurfaceFormat.BC1_SRGB:
|
|
case SurfaceFormat.BC2_UNORM:
|
|
case SurfaceFormat.BC2_SRGB:
|
|
case SurfaceFormat.BC3_UNORM:
|
|
case SurfaceFormat.BC3_SRGB:
|
|
case SurfaceFormat.BC4_UNORM:
|
|
case SurfaceFormat.BC4_SNORM:
|
|
case SurfaceFormat.BC5_UNORM:
|
|
case SurfaceFormat.BC5_SNORM:
|
|
case SurfaceFormat.BC6_UFLOAT:
|
|
case SurfaceFormat.BC6_FLOAT:
|
|
case SurfaceFormat.BC7_UNORM:
|
|
case SurfaceFormat.BC7_SRGB:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
private static bool IsAtscFormat(SurfaceFormat Format)
|
|
{
|
|
switch (Format)
|
|
{
|
|
case SurfaceFormat.ASTC_10x10_SRGB:
|
|
case SurfaceFormat.ASTC_10x10_UNORM:
|
|
case SurfaceFormat.ASTC_10x5_SRGB:
|
|
case SurfaceFormat.ASTC_10x5_UNORM:
|
|
case SurfaceFormat.ASTC_10x6_SRGB:
|
|
case SurfaceFormat.ASTC_10x6_UNORM:
|
|
case SurfaceFormat.ASTC_10x8_SRGB:
|
|
case SurfaceFormat.ASTC_10x8_UNORM:
|
|
case SurfaceFormat.ASTC_12x10_SRGB:
|
|
case SurfaceFormat.ASTC_12x10_UNORM:
|
|
case SurfaceFormat.ASTC_12x12_SRGB:
|
|
case SurfaceFormat.ASTC_12x12_UNORM:
|
|
case SurfaceFormat.ASTC_4x4_SRGB:
|
|
case SurfaceFormat.ASTC_5x4_SRGB:
|
|
case SurfaceFormat.ASTC_5x4_UNORM:
|
|
case SurfaceFormat.ASTC_5x5_SRGB:
|
|
case SurfaceFormat.ASTC_5x5_UNORM:
|
|
case SurfaceFormat.ASTC_6x5_SRGB:
|
|
case SurfaceFormat.ASTC_6x5_UNORM:
|
|
case SurfaceFormat.ASTC_6x6_SRGB:
|
|
case SurfaceFormat.ASTC_6x6_UNORM:
|
|
case SurfaceFormat.ASTC_8x5_SRGB:
|
|
case SurfaceFormat.ASTC_8x5_UNORM:
|
|
case SurfaceFormat.ASTC_8x6_SRGB:
|
|
case SurfaceFormat.ASTC_8x6_UNORM:
|
|
case SurfaceFormat.ASTC_8x8_SRGB:
|
|
case SurfaceFormat.ASTC_8x8_UNORM:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
public static Bitmap SwapBlueRedChannels(Bitmap bitmap)
|
|
{
|
|
return ColorComponentSelector(bitmap, ChannelType.Blue, ChannelType.Green, ChannelType.Red, ChannelType.Alpha);
|
|
}
|
|
public static byte[] CompressBlock(byte[] data, int width, int height, SurfaceFormat format)
|
|
{
|
|
if (IsCompressedFormat(format))
|
|
return DDSCompressor.CompressBlock(data, width, height, GetCompressedDXGI_FORMAT(format));
|
|
else if (IsAtscFormat(format))
|
|
return null;
|
|
else
|
|
return DDSCompressor.EncodePixelBlock(data, width, height, GetUncompressedDXGI_FORMAT(format));
|
|
}
|
|
public unsafe Bitmap GLTextureToBitmap(BRTI_Texture 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 unsafe void ExportAsImage(BRTI_Texture t, int id, string path)
|
|
{
|
|
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);
|
|
bitmap.Save(path);
|
|
}
|
|
public class BRTI_Texture
|
|
{
|
|
public List<byte[]> mipmaps = new List<byte[]>();
|
|
public byte[] data;
|
|
public int width, height;
|
|
public int display = 0;
|
|
public PixelInternalFormat type;
|
|
public OpenTK.Graphics.OpenGL.PixelFormat utype;
|
|
}
|
|
public static int getImageSize(BRTI_Texture t)
|
|
{
|
|
switch (t.type)
|
|
{
|
|
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 static int loadImage(BRTI_Texture t)
|
|
{
|
|
int texID = GL.GenTexture();
|
|
|
|
GL.BindTexture(TextureTarget.Texture2D, texID);
|
|
|
|
if (t.type != PixelInternalFormat.Rgba)
|
|
{
|
|
GL.CompressedTexImage2D<byte>(TextureTarget.Texture2D, 0, (InternalFormat)t.type,
|
|
t.width, t.height, 0, getImageSize(t), t.data);
|
|
//Debug.WriteLine(GL.GetError());
|
|
}
|
|
else
|
|
{
|
|
GL.TexImage2D<byte>(TextureTarget.Texture2D, 0, t.type, t.width, t.height, 0,
|
|
t.utype, PixelType.UnsignedByte, t.data);
|
|
}
|
|
|
|
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
|
|
|
|
return texID;
|
|
}
|
|
private void Remove(object sender, EventArgs args)
|
|
{
|
|
((BinaryTextureContainer)Parent).RemoveTexture(this);
|
|
}
|
|
private void Rename(object sender, EventArgs args)
|
|
{
|
|
RenameDialog dialog = new RenameDialog();
|
|
dialog.SetString(Text);
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
((BinaryTextureContainer)Parent).Textures.Remove(Text);
|
|
Text = dialog.textBox1.Text;
|
|
|
|
((BinaryTextureContainer)Parent).Textures.Add(Text, this);
|
|
}
|
|
}
|
|
private void Replace(object sender, EventArgs args)
|
|
{
|
|
OpenFileDialog ofd = new OpenFileDialog();
|
|
ofd.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(*.*)|*.*";
|
|
|
|
ofd.Multiselect = false;
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
Replace(ofd.FileName);
|
|
}
|
|
}
|
|
public void Replace(string FileName)
|
|
{
|
|
string ext = Path.GetExtension(FileName);
|
|
ext = ext.ToLower();
|
|
|
|
TextureImporterSettings setting = new TextureImporterSettings();
|
|
BinaryTextureImporterList importer = new BinaryTextureImporterList();
|
|
|
|
switch (ext)
|
|
{
|
|
case ".bftex":
|
|
Texture.Import(FileName);
|
|
break;
|
|
case ".dds":
|
|
setting.LoadDDS(FileName, bntxFile, null, this);
|
|
break;
|
|
default:
|
|
setting.LoadBitMap(FileName, bntxFile);
|
|
importer.LoadSetting(setting, (BinaryTextureContainer)Parent);
|
|
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)
|
|
{
|
|
Texture = setting.FromBitMap(setting.DataBlockOutput[0], setting);
|
|
LoadOpenGLTexture();
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("Something went wrong???");
|
|
}
|
|
Texture.Name = Text;
|
|
UpdateBfresTextureMapping();
|
|
UpdateBNTXEditor();
|
|
}
|
|
}
|
|
private void UpdateBfresTextureMapping()
|
|
{
|
|
foreach (GL_Core.Interfaces.AbstractGlDrawable draw in Runtime.abstractGlDrawables)
|
|
{
|
|
if (draw is BFRESRender)
|
|
{
|
|
((BFRESRender)draw).UpdateTextureMaps();
|
|
}
|
|
}
|
|
}
|
|
private void Export(object sender, EventArgs args)
|
|
{
|
|
SaveFileDialog sfd = new SaveFileDialog();
|
|
sfd.FileName = Texture.Name;
|
|
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 Export(string FileName, bool ExportSurfaceLevel = false,
|
|
bool ExportMipMapLevel = false, int SurfaceLevel = 0, int MipLevel = 0)
|
|
{
|
|
string ext = 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 = Texture.Width;
|
|
dds.header.height = Texture.Height;
|
|
dds.header.mipmapCount = (uint)mipmaps.Count;
|
|
dds.header.pitchOrLinearSize = (uint)mipmaps[0][0].Length;
|
|
|
|
if (IsCompressedFormat(Texture.Format))
|
|
dds.SetFlags(GetCompressedDXGI_FORMAT(Texture.Format));
|
|
else
|
|
dds.SetFlags(GetUncompressedDXGI_FORMAT(Texture.Format));
|
|
|
|
dds.Save(dds, FileName, mipmaps);
|
|
}
|
|
public void LoadTexture(Texture tex, int target = 1)
|
|
{
|
|
mipmaps.Clear();
|
|
|
|
try
|
|
{
|
|
uint blk_dim = Formats.blk_dims((uint)((int)tex.Format >> 8));
|
|
uint blkWidth = blk_dim >> 4;
|
|
uint blkHeight = blk_dim & 0xF;
|
|
|
|
int linesPerBlockHeight = (1 << (int)tex.BlockHeightLog2) * 8;
|
|
|
|
uint bpp = Formats.bpps((uint)((int)tex.Format >> 8));
|
|
for (int arrayLevel = 0; arrayLevel < tex.ArrayLength; arrayLevel++)
|
|
{
|
|
int blockHeightShift = 0;
|
|
List<byte[]> mips = new List<byte[]>();
|
|
for (int mipLevel = 0; mipLevel < tex.TextureData[arrayLevel].Count; mipLevel++)
|
|
{
|
|
uint width = (uint)Math.Max(1, tex.Width >> mipLevel);
|
|
uint height = (uint)Math.Max(1, tex.Height >> mipLevel);
|
|
|
|
uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp;
|
|
|
|
if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight)
|
|
blockHeightShift += 1;
|
|
|
|
byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, (uint)tex.TileMode, (int)Math.Max(0, tex.BlockHeightLog2 - blockHeightShift), tex.TextureData[arrayLevel][mipLevel]);
|
|
//Create a copy and use that to remove uneeded data
|
|
byte[] result_ = new byte[size];
|
|
Array.Copy(result, 0, result_, 0, size);
|
|
mips.Add(result_);
|
|
|
|
}
|
|
mipmaps.Add(mips);
|
|
}
|
|
|
|
Texture = tex;
|
|
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
MessageBox.Show($"Failed to swizzle texture {Text}! Exception: {e}");
|
|
}
|
|
}
|
|
|
|
public Bitmap DisplayTexture(int DisplayMipIndex = 0, int ArrayIndex = 0)
|
|
{
|
|
LoadTexture(Texture);
|
|
|
|
if (mipmaps.Count <= 0)
|
|
{
|
|
throw new Exception("No texture data found");
|
|
}
|
|
|
|
uint width = (uint)Math.Max(1, Texture.Width >> DisplayMipIndex);
|
|
uint height = (uint)Math.Max(1, Texture.Height >> DisplayMipIndex);
|
|
|
|
byte[] data = mipmaps[ArrayIndex][DisplayMipIndex];
|
|
|
|
return DecodeBlock(data, width, height, Texture.Format);
|
|
}
|
|
|
|
public Bitmap ToBitmap()
|
|
{
|
|
return new Bitmap("");
|
|
}
|
|
public Bitmap UpdateBitmap(Bitmap image)
|
|
{
|
|
return ColorComponentSelector(image, Texture.ChannelRed, Texture.ChannelGreen, Texture.ChannelBlue, Texture.ChannelAlpha);
|
|
}
|
|
public static ChannelType[] SetChannelsByFormat(SurfaceFormat Format)
|
|
{
|
|
ChannelType[] channels = new ChannelType[4];
|
|
|
|
switch (Format)
|
|
{
|
|
case SurfaceFormat.BC5_UNORM:
|
|
case SurfaceFormat.BC5_SNORM:
|
|
channels[0] = ChannelType.Red;
|
|
channels[1] = ChannelType.Green;
|
|
channels[2] = ChannelType.Zero;
|
|
channels[3] = ChannelType.One;
|
|
break;
|
|
case SurfaceFormat.BC4_SNORM:
|
|
case SurfaceFormat.BC4_UNORM:
|
|
channels[0] = ChannelType.Red;
|
|
channels[1] = ChannelType.Red;
|
|
channels[2] = ChannelType.Red;
|
|
channels[3] = ChannelType.Red;
|
|
break;
|
|
default:
|
|
channels[0] = ChannelType.Red;
|
|
channels[1] = ChannelType.Green;
|
|
channels[2] = ChannelType.Blue;
|
|
channels[3] = ChannelType.Alpha;
|
|
break;
|
|
}
|
|
return channels;
|
|
}
|
|
public static Bitmap ColorComponentSelector(Bitmap image, ChannelType R, ChannelType G, ChannelType B, ChannelType A)
|
|
{
|
|
BitmapExtension.ColorSwapFilter color = new BitmapExtension.ColorSwapFilter();
|
|
if (R == ChannelType.Red)
|
|
color.CompRed = BitmapExtension.ColorSwapFilter.Red.Red;
|
|
if (R == ChannelType.Green)
|
|
color.CompRed = BitmapExtension.ColorSwapFilter.Red.Green;
|
|
if (R == ChannelType.Blue)
|
|
color.CompRed = BitmapExtension.ColorSwapFilter.Red.Blue;
|
|
if (R == ChannelType.Alpha)
|
|
color.CompRed = BitmapExtension.ColorSwapFilter.Red.Alpha;
|
|
if (R == ChannelType.One)
|
|
color.CompRed = BitmapExtension.ColorSwapFilter.Red.One;
|
|
if (R == ChannelType.Zero)
|
|
color.CompRed = BitmapExtension.ColorSwapFilter.Red.Zero;
|
|
|
|
if (G == ChannelType.Red)
|
|
color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Red;
|
|
if (G == ChannelType.Green)
|
|
color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Green;
|
|
if (G == ChannelType.Blue)
|
|
color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Blue;
|
|
if (G == ChannelType.Alpha)
|
|
color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Alpha;
|
|
if (G == ChannelType.One)
|
|
color.CompGreen = BitmapExtension.ColorSwapFilter.Green.One;
|
|
if (G == ChannelType.Zero)
|
|
color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Zero;
|
|
|
|
if (B == ChannelType.Red)
|
|
color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Red;
|
|
if (B == ChannelType.Green)
|
|
color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Green;
|
|
if (B == ChannelType.Blue)
|
|
color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Blue;
|
|
if (B == ChannelType.Alpha)
|
|
color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Alpha;
|
|
if (B == ChannelType.One)
|
|
color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.One;
|
|
if (B == ChannelType.Zero)
|
|
color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Zero;
|
|
|
|
if (A == ChannelType.Red)
|
|
color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Red;
|
|
if (A == ChannelType.Green)
|
|
color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Green;
|
|
if (A == ChannelType.Blue)
|
|
color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Blue;
|
|
if (A == ChannelType.Alpha)
|
|
color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Alpha;
|
|
if (A == ChannelType.One)
|
|
color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.One;
|
|
if (A == ChannelType.Zero)
|
|
color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Zero;
|
|
|
|
return BitmapExtension.SwapRGB(image, color);
|
|
}
|
|
|
|
private void SwapChannels(Bitmap bitmap)
|
|
{
|
|
for (int x = 0; x < bitmap.Width; x++)
|
|
{
|
|
for (int y = 0; y < bitmap.Height; y++)
|
|
{
|
|
bitmap.GetPixel(x, y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|