Add more stuff
This commit is contained in:
parent
98bb2c07be
commit
db31730291
334
Switch_FileFormatsMain/FileFormats/BFRES.cs
Normal file
334
Switch_FileFormatsMain/FileFormats/BFRES.cs
Normal file
@ -0,0 +1,334 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Switch_Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Switch_Toolbox.Library;
|
||||
using Switch_Toolbox.Library.Forms;
|
||||
using Switch_Toolbox.Library.IO;
|
||||
using Bfres.Structs;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class BFRES : 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[] { "BFRES", "*BFRES", "*BFRES" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.bfres", "*.sbfres" };
|
||||
public string Magic { get; set; } = "FRES";
|
||||
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
||||
public byte[] Data { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public IFileInfo IFileInfo { get; set; }
|
||||
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private TreeNodeFile eitorRoot;
|
||||
public TreeNodeFile EditorRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
return eitorRoot;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.eitorRoot = value;
|
||||
}
|
||||
}
|
||||
private void SaveFile()
|
||||
{
|
||||
List<IFileFormat> formats = new List<IFileFormat>();
|
||||
formats.Add(this);
|
||||
|
||||
SaveFileDialog sfd = new SaveFileDialog();
|
||||
sfd.Filter = Utils.GetAllFilters(formats);
|
||||
sfd.FileName = FileName;
|
||||
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
Cursor.Current = Cursors.WaitCursor;
|
||||
SaveCompressFile(Save(), sfd.FileName, Alignment);
|
||||
}
|
||||
}
|
||||
private void SaveCompressFile(byte[] data, string FileName, int Alignment = 0, bool EnableDialog = true)
|
||||
{
|
||||
if (EnableDialog && CompressionType != CompressionType.None)
|
||||
{
|
||||
DialogResult save = MessageBox.Show($"Compress file as {CompressionType}?", "File Save", MessageBoxButtons.YesNo);
|
||||
|
||||
if (save == DialogResult.Yes)
|
||||
{
|
||||
switch (CompressionType)
|
||||
{
|
||||
case CompressionType.Yaz0:
|
||||
data = EveryFileExplorer.YAZ0.Compress(data, Runtime.Yaz0CompressionLevel, (uint)Alignment);
|
||||
break;
|
||||
case CompressionType.Lz4f:
|
||||
data = STLibraryCompression.Type_LZ4F.Compress(data);
|
||||
break;
|
||||
case CompressionType.Lz4:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
File.WriteAllBytes(FileName, data);
|
||||
MessageBox.Show($"File has been saved to {FileName}");
|
||||
Cursor.Current = Cursors.Default;
|
||||
}
|
||||
|
||||
public bool IsActive { get; set; } = false;
|
||||
public bool UseEditMenu { get; set; } = false;
|
||||
public int Alignment { get; set; } = 0;
|
||||
public string FilePath { get; set; }
|
||||
public static bool IsWiiU = false;
|
||||
|
||||
BFRESRender bfres;
|
||||
public void Load()
|
||||
{
|
||||
IsActive = true;
|
||||
CanSave = true;
|
||||
|
||||
using (FileReader reader = new FileReader(new MemoryStream(Data)))
|
||||
{
|
||||
reader.Seek(4);
|
||||
if (reader.ReadInt32() != 0x20202020)
|
||||
{
|
||||
IsWiiU = true;
|
||||
}
|
||||
reader.Close();
|
||||
}
|
||||
|
||||
bfres = new BFRESRender();
|
||||
bfres.ResFileNode = new ResourceFile(this);
|
||||
bfres.ResFileNode.BFRESRender = bfres;
|
||||
bfres.SaveFile = SaveFile;
|
||||
|
||||
EditorRoot = bfres.ResFileNode;
|
||||
|
||||
if (IsWiiU)
|
||||
{
|
||||
bfres.LoadFile(new Syroot.NintenTools.Bfres.ResFile(new System.IO.MemoryStream(Data)));
|
||||
}
|
||||
else
|
||||
{
|
||||
bfres.LoadFile(new Syroot.NintenTools.NSW.Bfres.ResFile(new System.IO.MemoryStream(Data)));
|
||||
}
|
||||
|
||||
Runtime.abstractGlDrawables.Add(bfres);
|
||||
}
|
||||
public void Unload()
|
||||
{
|
||||
bfres.Destroy();
|
||||
bfres.ResFileNode.Nodes.Clear();
|
||||
}
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
MemoryStream mem = new MemoryStream();
|
||||
|
||||
if (IsWiiU)
|
||||
SaveWiiU(mem);
|
||||
else
|
||||
SaveSwitch(mem);
|
||||
|
||||
return mem.ToArray();
|
||||
}
|
||||
private void SaveSwitch(MemoryStream mem)
|
||||
{
|
||||
int CurMdl = 0;
|
||||
foreach (FMDL model in bfres.models)
|
||||
{
|
||||
bfres.resFile.Models[CurMdl].Shapes.Clear();
|
||||
bfres.resFile.Models[CurMdl].VertexBuffers.Clear();
|
||||
bfres.resFile.Models[CurMdl].Materials.Clear();
|
||||
bfres.resFile.Models[CurMdl].MaterialDict.Clear();
|
||||
|
||||
int i = 0;
|
||||
var duplicates = model.shapes.GroupBy(c => c.Text).Where(g => g.Skip(1).Any()).SelectMany(c => c);
|
||||
foreach (var shape in duplicates)
|
||||
shape.Text += i++;
|
||||
|
||||
foreach (FSHP shape in model.shapes)
|
||||
{
|
||||
CheckMissingTextures(shape);
|
||||
BfresSwitch.SetShape(shape, shape.Shape);
|
||||
|
||||
bfres.resFile.Models[CurMdl].Shapes.Add(shape.Shape);
|
||||
bfres.resFile.Models[CurMdl].VertexBuffers.Add(shape.VertexBuffer);
|
||||
|
||||
SetShaderAssignAttributes(shape.GetMaterial().shaderassign, shape);
|
||||
}
|
||||
foreach (FMAT mat in model.materials.Values)
|
||||
{
|
||||
BfresSwitch.SetMaterial(mat, mat.Material);
|
||||
bfres.resFile.Models[CurMdl].Materials.Add(mat.Material);
|
||||
}
|
||||
CurMdl++;
|
||||
}
|
||||
bfres.resFile.SkeletalAnims.Clear();
|
||||
if (EditorRoot.Nodes.ContainsKey("FSKA"))
|
||||
{
|
||||
foreach (BfresSkeletonAnim ska in EditorRoot.Nodes["FSKA"].Nodes)
|
||||
{
|
||||
bfres.resFile.SkeletalAnims.Add(ska.SkeletalAnim);
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCheck();
|
||||
|
||||
BfresSwitch.WriteExternalFiles(bfres.resFile, EditorRoot);
|
||||
bfres.resFile.Save(mem);
|
||||
}
|
||||
private void SaveWiiU(MemoryStream mem)
|
||||
{
|
||||
bfres.resFileU.Save(mem);
|
||||
|
||||
int CurMdl = 0;
|
||||
foreach (FMDL model in bfres.models)
|
||||
{
|
||||
bfres.resFileU.Models[CurMdl].Shapes.Clear();
|
||||
bfres.resFileU.Models[CurMdl].VertexBuffers.Clear();
|
||||
bfres.resFileU.Models[CurMdl].Materials.Clear();
|
||||
|
||||
int i = 0;
|
||||
var duplicates = model.shapes.GroupBy(c => c.Text).Where(g => g.Skip(1).Any()).SelectMany(c => c);
|
||||
foreach (var shape in duplicates)
|
||||
shape.Text += i++;
|
||||
|
||||
foreach (FSHP shape in model.shapes)
|
||||
{
|
||||
CheckMissingTextures(shape);
|
||||
BfresWiiU.SetShape(shape, shape.ShapeU);
|
||||
|
||||
bfres.resFileU.Models[CurMdl].Shapes.Add(shape.Text, shape.ShapeU);
|
||||
bfres.resFileU.Models[CurMdl].VertexBuffers.Add(shape.VertexBufferU);
|
||||
|
||||
SetShaderAssignAttributes(shape.GetMaterial().shaderassign, shape);
|
||||
}
|
||||
foreach (FMAT mat in model.materials.Values)
|
||||
{
|
||||
BfresWiiU.SetMaterial(mat, mat.MaterialU);
|
||||
bfres.resFileU.Models[CurMdl].Materials.Add(mat.Text, mat.MaterialU);
|
||||
}
|
||||
CurMdl++;
|
||||
}
|
||||
bfres.resFile.SkeletalAnims.Clear();
|
||||
if (EditorRoot.Nodes.ContainsKey("FSKA"))
|
||||
{
|
||||
foreach (BfresSkeletonAnim ska in EditorRoot.Nodes["FSKA"].Nodes)
|
||||
{
|
||||
bfres.resFile.SkeletalAnims.Add(ska.SkeletalAnim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetShaderAssignAttributes(FMAT.ShaderAssign shd, FSHP shape)
|
||||
{
|
||||
foreach (var att in shape.vertexAttributes)
|
||||
{
|
||||
if (!shd.attributes.ContainsValue(att.Name) && !shd.attributes.ContainsKey(att.Name))
|
||||
shd.attributes.Add(att.Name, att.Name);
|
||||
}
|
||||
foreach (var tex in shape.GetMaterial().textures)
|
||||
{
|
||||
if (!shd.samplers.ContainsValue(tex.SamplerName))
|
||||
shd.attributes.Add(tex.SamplerName, tex.SamplerName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SetDuplicateShapeName(FSHP shape)
|
||||
{
|
||||
DialogResult dialogResult = MessageBox.Show($"A shape {shape.Text} already exists with that name", "", MessageBoxButtons.OK);
|
||||
|
||||
if (dialogResult == DialogResult.OK)
|
||||
{
|
||||
RenameDialog renameDialog = new RenameDialog();
|
||||
renameDialog.Text = "Rename Texture";
|
||||
if (renameDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
shape.Text = renameDialog.textBox1.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ImportMissingTextures = false;
|
||||
private void CheckMissingTextures(FSHP shape)
|
||||
{
|
||||
foreach (BinaryTextureContainer bntx in PluginRuntime.bntxContainers)
|
||||
{
|
||||
foreach (MatTexture tex in shape.GetMaterial().textures)
|
||||
{
|
||||
if (!bntx.Textures.ContainsKey(tex.Name))
|
||||
{
|
||||
if (!ImportMissingTextures)
|
||||
{
|
||||
DialogResult result = MessageBox.Show("Missing textures found! Would you like to use placeholders?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
ImportMissingTextures = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImportMissingTextures)
|
||||
bntx.ImportPlaceholderTexture(tex.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ErrorCheck()
|
||||
{
|
||||
if (bfres != null)
|
||||
{
|
||||
List<Errors> Errors = new List<Errors>();
|
||||
foreach (FMDL model in bfres.models)
|
||||
{
|
||||
foreach (FSHP shp in model.shapes)
|
||||
{
|
||||
Syroot.NintenTools.NSW.Bfres.VertexBuffer vtx = shp.VertexBuffer;
|
||||
Syroot.NintenTools.NSW.Bfres.Material mat = shp.GetMaterial().Material;
|
||||
Syroot.NintenTools.NSW.Bfres.ShaderAssign shdr = mat.ShaderAssign;
|
||||
|
||||
for (int att = 0; att < vtx.Attributes.Count; att++)
|
||||
{
|
||||
if (!shdr.AttribAssigns.Contains(vtx.Attributes[att].Name))
|
||||
MessageBox.Show($"Error! Attribute {vtx.Attributes[att].Name} is unlinked!");
|
||||
}
|
||||
for (int att = 0; att < mat.TextureRefs.Count; att++)
|
||||
{
|
||||
if (!shdr.SamplerAssigns.Contains(mat.SamplerDict.GetKey(att))) //mat.SamplerDict[att]
|
||||
MessageBox.Show($"Error! Sampler {mat.SamplerDict.GetKey(att)} is unlinked!");
|
||||
}
|
||||
}
|
||||
}
|
||||
// ErrorList errorList = new ErrorList();
|
||||
// errorList.LoadList(Errors);
|
||||
// errorList.Show();
|
||||
}
|
||||
}
|
||||
public class Errors
|
||||
{
|
||||
public string Section = "None";
|
||||
public string Section2 = "None";
|
||||
public string Message = "";
|
||||
public string Type = "Unkown";
|
||||
}
|
||||
}
|
||||
}
|
201
Switch_FileFormatsMain/FileFormats/BYAML.cs
Normal file
201
Switch_FileFormatsMain/FileFormats/BYAML.cs
Normal file
@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Switch_Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Switch_Toolbox.Library;
|
||||
using ByamlExt.Byaml;
|
||||
using ByamlExt;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class BYAML : 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[] { "BYAML" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.byaml", "*.byml", "*.bprm", "*.sbyml" };
|
||||
public string Magic { get; set; } = "YB";
|
||||
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 string FilePath { get; set; }
|
||||
public IFileInfo IFileInfo { get; set; }
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
class EditableNode
|
||||
{
|
||||
public Type type { get => Node[Index].GetType(); }
|
||||
dynamic Node;
|
||||
dynamic Index;
|
||||
|
||||
public dynamic Get() => Node[Index];
|
||||
public void Set(dynamic value) => Node[Index] = value;
|
||||
public string GetTreeViewString()
|
||||
{
|
||||
if (Index is int)
|
||||
return Node[Index].ToString();
|
||||
else
|
||||
return Index + " : " + Node[Index].ToString();
|
||||
}
|
||||
|
||||
public EditableNode(dynamic _node, dynamic _index)
|
||||
{
|
||||
Node = _node;
|
||||
Index = _index;
|
||||
}
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
IsActive = false;
|
||||
CanSave = false;
|
||||
|
||||
// ByamlViewer.OpenByml(new System.IO.MemoryStream(Data), FileName);
|
||||
|
||||
|
||||
// BymlFileData byamlFile = ByamlFile.LoadN(new System.IO.MemoryStream(Data), false, Syroot.BinaryData.ByteOrder.LittleEndian);
|
||||
// EditorRoot = LoadByamlNodes(byamlFile.RootNode);
|
||||
|
||||
// LoadDockedEditor(byamlFile);
|
||||
}
|
||||
public void Unload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ByamlEditor ByamlEditor;
|
||||
|
||||
public void LoadDockedEditor(BymlFileData byamlFile)
|
||||
{
|
||||
foreach (Control control in FirstPlugin.MainF.Controls)
|
||||
{
|
||||
if (control is DockPanel)
|
||||
{
|
||||
ByamlEditor = new ByamlEditor();
|
||||
ByamlEditor.Dock = DockStyle.Fill;
|
||||
ByamlEditor.Show(((DockPanel)control), DockState.Document);
|
||||
ByamlEditor.LoadByaml(byamlFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TreeNode LoadByamlNodes(dynamic root)
|
||||
{
|
||||
TreeNode node = new TreeNode();
|
||||
|
||||
if (root == null)
|
||||
return node;
|
||||
if (root is Dictionary<string, dynamic>)
|
||||
{
|
||||
parseDictNode(root, node.Nodes);
|
||||
}
|
||||
else if (root is List<dynamic>)
|
||||
{
|
||||
if (((List<dynamic>)root).Count == 0)
|
||||
{
|
||||
MessageBox.Show("This byml is empty");
|
||||
}
|
||||
parseArrayNode(root, node.Nodes);
|
||||
}
|
||||
else if (root is List<ByamlPathPoint>)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void parseArrayNode(IList<dynamic> list, TreeNodeCollection addto)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (dynamic k in list)
|
||||
{
|
||||
if (k is IDictionary<string, dynamic>)
|
||||
{
|
||||
TreeNode current = addto.Add("<Dictionary>");
|
||||
current.Tag = ((IDictionary<string, dynamic>)k);
|
||||
current.Nodes.Add("✯✯dummy✯✯");
|
||||
}
|
||||
else if (k is IList<dynamic>)
|
||||
{
|
||||
TreeNode current = addto.Add("<Array>");
|
||||
current.Tag = ((IList<dynamic>)k);
|
||||
current.Nodes.Add("✯✯dummy✯✯");
|
||||
}
|
||||
else if (k is IList<ByamlPathPoint>)
|
||||
{
|
||||
TreeNode current = addto.Add("<PathPointArray>");
|
||||
current.Tag = ((IList<ByamlPathPoint>)k);
|
||||
parsePathPointArray(k, current.Nodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
var n = addto.Add(k == null ? "<NULL>" : k.ToString());
|
||||
if (k != null) n.Tag = new EditableNode(list, index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
void parseDictNode(IDictionary<string, dynamic> node, TreeNodeCollection addto)
|
||||
{
|
||||
foreach (string k in node.Keys)
|
||||
{
|
||||
TreeNode current = addto.Add(k);
|
||||
if (node[k] is IDictionary<string, dynamic>)
|
||||
{
|
||||
current.Text += " : <Dictionary>";
|
||||
current.Tag = node[k];
|
||||
current.Nodes.Add("✯✯dummy✯✯"); //a text that can't be in a byml
|
||||
}
|
||||
else if (node[k] is IList<dynamic>)
|
||||
{
|
||||
current.Text += " : <Array>";
|
||||
current.Tag = ((IList<dynamic>)node[k]);
|
||||
current.Nodes.Add("✯✯dummy✯✯");
|
||||
}
|
||||
else if (node[k] is IList<ByamlPathPoint>)
|
||||
{
|
||||
current.Text += " : <PathPointArray>";
|
||||
current.Tag = ((IList<ByamlPathPoint>)node[k]);
|
||||
parsePathPointArray(node[k], current.Nodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
current.Text = current.Text + " : " + (node[k] == null ? "<NULL>" : node[k].ToString());
|
||||
if (node[k] != null) current.Tag = new EditableNode(node, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
void parsePathPointArray(IList<ByamlPathPoint> list, TreeNodeCollection addto)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (var k in list)
|
||||
{
|
||||
index++;
|
||||
var n = addto.Add(k == null ? "<NULL>" : k.ToString());
|
||||
if (k != null) n.Tag = new EditableNode(list, index);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Switch_Toolbox;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Switch_Toolbox.Library;
|
||||
using KCLExt;
|
||||
using SFGraphics.GLObjects.Shaders;
|
||||
using Smash_Forge.Rendering;
|
||||
using GL_Core.Interfaces;
|
||||
@ -15,6 +11,8 @@ using OpenTK;
|
||||
using Switch_Toolbox.Library.Rendering;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
using GL_Core;
|
||||
using System.Drawing;
|
||||
using Switch_Toolbox.Library.IO;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
@ -29,11 +27,12 @@ namespace FirstPlugin
|
||||
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
||||
public byte[] Data { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public TreeNode EditorRoot { 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
|
||||
@ -46,7 +45,8 @@ namespace FirstPlugin
|
||||
public void Load()
|
||||
{
|
||||
IsActive = true;
|
||||
EditorRoot = new KCLRoot(FileName);
|
||||
EditorRoot = new KCLRoot(FileName, this);
|
||||
IFileInfo = new IFileInfo();
|
||||
}
|
||||
public void Unload()
|
||||
{
|
||||
@ -54,7 +54,34 @@ namespace FirstPlugin
|
||||
}
|
||||
public byte[] Save()
|
||||
{
|
||||
return null;
|
||||
KCLRoot root = (KCLRoot)EditorRoot;
|
||||
return root.kcl.Write(Syroot.BinaryData.ByteOrder.LittleEndian);
|
||||
}
|
||||
|
||||
private static void SaveCompressFile(byte[] data, string FileName, CompressionType CompressionType, int Alignment = 0, bool EnableDialog = true)
|
||||
{
|
||||
if (EnableDialog && CompressionType != CompressionType.None)
|
||||
{
|
||||
DialogResult save = MessageBox.Show($"Compress file as {CompressionType}?", "File Save", MessageBoxButtons.YesNo);
|
||||
|
||||
if (save == DialogResult.Yes)
|
||||
{
|
||||
switch (CompressionType)
|
||||
{
|
||||
case CompressionType.Yaz0:
|
||||
data = EveryFileExplorer.YAZ0.Compress(data, Runtime.Yaz0CompressionLevel, (uint)Alignment);
|
||||
break;
|
||||
case CompressionType.Lz4f:
|
||||
data = STLibraryCompression.Type_LZ4F.Compress(data);
|
||||
break;
|
||||
case CompressionType.Lz4:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
File.WriteAllBytes(FileName, data);
|
||||
MessageBox.Show($"File has been saved to {FileName}");
|
||||
Cursor.Current = Cursors.Default;
|
||||
}
|
||||
|
||||
public enum GameSet : ushort
|
||||
@ -117,23 +144,152 @@ namespace FirstPlugin
|
||||
BoostTrick = 8202,
|
||||
}
|
||||
|
||||
public static Shader shader = null;
|
||||
|
||||
public class KCLRoot : TreeNodeCustom
|
||||
public class KCLRoot : TreeNodeFile
|
||||
{
|
||||
public KCLRoot(string Name)
|
||||
public KCLRoot(string Name, IFileFormat handler)
|
||||
{
|
||||
Text = Name;
|
||||
FileHandler = handler;
|
||||
Renderer = new KCLRendering();
|
||||
Read(handler.Data);
|
||||
|
||||
ContextMenu = new ContextMenu();
|
||||
MenuItem save = new MenuItem("Save");
|
||||
ContextMenu.MenuItems.Add(save);
|
||||
save.Click += Save;
|
||||
MenuItem export = new MenuItem("Export");
|
||||
ContextMenu.MenuItems.Add(export);
|
||||
export.Click += Export;
|
||||
MenuItem replace = new MenuItem("Replace");
|
||||
ContextMenu.MenuItems.Add(replace);
|
||||
replace.Click += Replace;
|
||||
}
|
||||
public void Save(object sender, EventArgs args)
|
||||
{
|
||||
SaveFileDialog sfd = new SaveFileDialog();
|
||||
sfd.Filter = "Supported Formats|*.kcl";
|
||||
sfd.FileName = Text;
|
||||
sfd.DefaultExt = ".kcl";
|
||||
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
|
||||
int Alignment = FileHandler.IFileInfo.Alignment;
|
||||
SaveCompressFile(FileHandler.Save(), sfd.FileName, FileHandler.CompressionType, Alignment);
|
||||
}
|
||||
}
|
||||
public void Export(object sender, EventArgs args)
|
||||
{
|
||||
if (kcl == null)
|
||||
return;
|
||||
|
||||
SaveFileDialog sfd = new SaveFileDialog();
|
||||
sfd.Filter = "Supported Formats|*.obj";
|
||||
sfd.FileName = Text;
|
||||
sfd.DefaultExt = ".obj";
|
||||
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
kcl.ToOBJ().toWritableObj().WriteObj(sfd.FileName + ".obj");
|
||||
}
|
||||
}
|
||||
public void Replace(object sender, EventArgs args)
|
||||
{
|
||||
OpenFileDialog ofd = new OpenFileDialog();
|
||||
ofd.Filter = "Supported Formats|*.obj";
|
||||
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
var mod = EditorCore.Common.OBJ.Read(new MemoryStream(File.ReadAllBytes(ofd.FileName)), null);
|
||||
if (mod.Faces.Count > 65535)
|
||||
{
|
||||
MessageBox.Show("this model has too many faces, only models with less than 65535 triangles can be converted");
|
||||
return;
|
||||
}
|
||||
kcl = MarioKart.MK7.KCL.FromOBJ(mod);
|
||||
Read(kcl.Write(Syroot.BinaryData.ByteOrder.LittleEndian));
|
||||
}
|
||||
}
|
||||
|
||||
KCLRendering Renderer;
|
||||
public override void OnClick(TreeView treeView)
|
||||
{
|
||||
//If has models
|
||||
if (Nodes[0].Nodes.Count > 0)
|
||||
Renderer.LoadViewport();
|
||||
Renderer.UpdateVertexData();
|
||||
}
|
||||
|
||||
public MarioKart.MK7.KCL kcl = null;
|
||||
public void Read(byte[] file_data)
|
||||
{
|
||||
try
|
||||
{
|
||||
Renderer.LoadViewport();
|
||||
Renderer.UpdateVertexData();
|
||||
kcl = new MarioKart.MK7.KCL(file_data, Syroot.BinaryData.ByteOrder.LittleEndian);
|
||||
}
|
||||
catch
|
||||
{
|
||||
kcl = new MarioKart.MK7.KCL(file_data, Syroot.BinaryData.ByteOrder.BigEndian);
|
||||
}
|
||||
Read(kcl);
|
||||
Renderer.UpdateVertexData();
|
||||
}
|
||||
public void Read(MarioKart.MK7.KCL kcl)
|
||||
{
|
||||
Nodes.Clear();
|
||||
Renderer.models.Clear();
|
||||
|
||||
int CurModelIndx = 0;
|
||||
foreach (MarioKart.MK7.KCL.KCLModel mdl in kcl.Models)
|
||||
{
|
||||
KCLModel kclmodel = new KCLModel();
|
||||
|
||||
kclmodel.Text = "Model " + CurModelIndx;
|
||||
|
||||
int ft = 0;
|
||||
foreach (var plane in mdl.Planes)
|
||||
{
|
||||
var triangle = mdl.GetTriangle(plane);
|
||||
var normal = triangle.Normal;
|
||||
var pointA = triangle.PointA;
|
||||
var pointB = triangle.PointB;
|
||||
var pointC = triangle.PointC;
|
||||
|
||||
Vertex vtx = new Vertex();
|
||||
Vertex vtx2 = new Vertex();
|
||||
Vertex vtx3 = new Vertex();
|
||||
|
||||
vtx.pos = new Vector3(Vec3D_To_Vec3(pointA));
|
||||
vtx2.pos = new Vector3(Vec3D_To_Vec3(pointB));
|
||||
vtx3.pos = new Vector3(Vec3D_To_Vec3(pointC));
|
||||
vtx.nrm = new Vector3(Vec3D_To_Vec3(normal));
|
||||
vtx2.nrm = new Vector3(Vec3D_To_Vec3(normal));
|
||||
vtx3.nrm = new Vector3(Vec3D_To_Vec3(normal));
|
||||
|
||||
KCLModel.Face face = new KCLModel.Face();
|
||||
face.Text = triangle.Collision.ToString();
|
||||
face.MaterialFlag = triangle.Collision;
|
||||
|
||||
var col = MarioKart.MK7.KCLColors.GetMaterialColor(plane.CollisionType);
|
||||
Vector3 ColorSet = new Vector3(col.R, col.G, col.B);
|
||||
|
||||
vtx.col = new Vector4(ColorSet, 1);
|
||||
vtx2.col = new Vector4(ColorSet, 1);
|
||||
vtx3.col = new Vector4(ColorSet, 1);
|
||||
|
||||
kclmodel.faces.Add(ft);
|
||||
kclmodel.faces.Add(ft + 1);
|
||||
kclmodel.faces.Add(ft + 2);
|
||||
|
||||
ft += 3;
|
||||
|
||||
kclmodel.vertices.Add(vtx);
|
||||
kclmodel.vertices.Add(vtx2);
|
||||
kclmodel.vertices.Add(vtx3);
|
||||
}
|
||||
|
||||
Renderer.models.Add(kclmodel);
|
||||
Nodes.Add(kclmodel);
|
||||
|
||||
CurModelIndx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,15 +303,25 @@ namespace FirstPlugin
|
||||
//Set the game's material list
|
||||
public GameSet GameMaterialSet = GameSet.MarioKart8D;
|
||||
public List<KCLModel> models = new List<KCLModel>();
|
||||
public Shader shader = null;
|
||||
|
||||
public KCLRendering()
|
||||
private void GenerateBuffers()
|
||||
{
|
||||
GL.GenBuffers(1, out vbo_position);
|
||||
GL.GenBuffers(1, out ibo_elements);
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
GL.DeleteBuffer(vbo_position);
|
||||
GL.DeleteBuffer(ibo_elements);
|
||||
}
|
||||
|
||||
public void UpdateVertexData()
|
||||
{
|
||||
if (OpenTKSharedResources.SetupStatus == OpenTKSharedResources.SharedResourceStatus.Unitialized)
|
||||
return;
|
||||
|
||||
DisplayVertex[] Vertices;
|
||||
int[] Faces;
|
||||
|
||||
@ -169,8 +335,6 @@ namespace FirstPlugin
|
||||
List<DisplayVertex> pv = m.CreateDisplayVertices();
|
||||
Vs.AddRange(pv);
|
||||
|
||||
Console.WriteLine(m.displayFaceSize);
|
||||
|
||||
for (int i = 0; i < m.displayFaceSize; i++)
|
||||
{
|
||||
Ds.Add(m.display[i] + voffset);
|
||||
@ -189,6 +353,8 @@ namespace FirstPlugin
|
||||
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
|
||||
GL.BufferData<int>(BufferTarget.ElementArrayBuffer, (IntPtr)(Faces.Length * sizeof(int)), Faces, BufferUsageHint.StaticDraw);
|
||||
|
||||
Viewport.Instance.UpdateViewport();
|
||||
}
|
||||
|
||||
string FileName;
|
||||
@ -226,9 +392,16 @@ namespace FirstPlugin
|
||||
}
|
||||
public override void Draw(GL_ControlModern control)
|
||||
{
|
||||
shader = OpenTKSharedResources.shaders["KCL"];
|
||||
bool buffersWereInitialized = ibo_elements != 0 && vbo_position != 0;
|
||||
if (!buffersWereInitialized)
|
||||
GenerateBuffers();
|
||||
|
||||
if (OpenTKSharedResources.SetupStatus == OpenTKSharedResources.SharedResourceStatus.Unitialized)
|
||||
return;
|
||||
|
||||
shader = OpenTKSharedResources.shaders["KCL"];
|
||||
shader.UseProgram();
|
||||
|
||||
shader.EnableVertexAttributes();
|
||||
SetRenderSettings(shader);
|
||||
|
||||
@ -237,10 +410,13 @@ namespace FirstPlugin
|
||||
Matrix4 camMat = previewScale * control.mtxCam * control.mtxProj;
|
||||
|
||||
shader.SetVector3("difLightDirection", Vector3.TransformNormal(new Vector3(0f, 0f, -1f), camMat.Inverted()).Normalized());
|
||||
shader.SetVector3("difLightColor", new Vector3(1));
|
||||
shader.SetVector3("ambLightColor", new Vector3(1));
|
||||
|
||||
shader.EnableVertexAttributes();
|
||||
SetRenderSettings(shader);
|
||||
|
||||
shader.SetMatrix4x4("modelview", ref camMat);
|
||||
shader.SetMatrix4x4("mvpMatrix", ref camMat);
|
||||
|
||||
foreach (KCLModel mdl in models)
|
||||
{
|
||||
@ -318,138 +494,44 @@ namespace FirstPlugin
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
||||
shader.SetInt("colorOverride", 0);
|
||||
}
|
||||
|
||||
public MarioKart.MK7.KCL kcl = null;
|
||||
public void Read(byte[] file_data)
|
||||
{
|
||||
try
|
||||
{
|
||||
kcl = new MarioKart.MK7.KCL(file_data, Syroot.BinaryData.ByteOrder.LittleEndian);
|
||||
}
|
||||
catch
|
||||
{
|
||||
kcl = new MarioKart.MK7.KCL(file_data, Syroot.BinaryData.ByteOrder.BigEndian);
|
||||
}
|
||||
|
||||
/*
|
||||
int CurModelIndx = 0;
|
||||
foreach (MarioKart.MK7.KCL.KCLModel mdl in kcl.Models)
|
||||
{
|
||||
KCLModel kclmodel = new KCLModel();
|
||||
|
||||
kclmodel.Text = "Model " + CurModelIndx;
|
||||
|
||||
KclFace[] indicesArray = mdl.Faces;
|
||||
|
||||
int ft = 0;
|
||||
foreach (KclFace f in mdl.Faces)
|
||||
{
|
||||
Vertex vtx = new Vertex();
|
||||
Vertex vtx2 = new Vertex();
|
||||
Vertex vtx3 = new Vertex();
|
||||
|
||||
|
||||
Vector3 CrossA = Vector3.Cross(Vec3F_To_Vec3(mdl.Normals[f.Normal1Index]), Vec3F_To_Vec3(mdl.Normals[f.DirectionIndex]));
|
||||
Vector3 CrossB = Vector3.Cross(Vec3F_To_Vec3(mdl.Normals[f.Normal2Index]), Vec3F_To_Vec3(mdl.Normals[f.DirectionIndex]));
|
||||
Vector3 CrossC = Vector3.Cross(Vec3F_To_Vec3(mdl.Normals[f.Normal3Index]), Vec3F_To_Vec3(mdl.Normals[f.DirectionIndex]));
|
||||
Vector3 normal_a = Vec3F_To_Vec3(mdl.Normals[f.Normal1Index]);
|
||||
Vector3 normal_b = Vec3F_To_Vec3(mdl.Normals[f.Normal2Index]);
|
||||
Vector3 normal_c = Vec3F_To_Vec3(mdl.Normals[f.Normal3Index]);
|
||||
|
||||
|
||||
float result1 = Vector3.Dot(new Vector3(CrossB.X, CrossB.Y, CrossB.Z), (new Vector3(normal_c.X, normal_c.Y, normal_c.Z)));
|
||||
float result2 = Vector3.Dot(new Vector3(CrossA.X, CrossA.Y, CrossA.Z), (new Vector3(normal_c.X, normal_c.Y, normal_c.Z)));
|
||||
|
||||
Vector3 pos = Vec3F_To_Vec3(mdl.Positions[f.PositionIndex]);
|
||||
Vector3 nrm = Vec3F_To_Vec3(mdl.Normals[f.Normal1Index]);
|
||||
|
||||
Vector3 Vertex1 = pos;
|
||||
Vector3 Vertex2 = pos + CrossB * (f.Length / result1);
|
||||
Vector3 Vertex3 = pos + CrossA * (f.Length / result2);
|
||||
|
||||
vtx.pos = new Vector3(Vertex1.X, Vertex1.Y, Vertex1.Z);
|
||||
vtx2.pos = new Vector3(Vertex2.X, Vertex2.Y, Vertex2.Z);
|
||||
vtx3.pos = new Vector3(Vertex3.X, Vertex3.Y, Vertex3.Z);
|
||||
|
||||
var dir = Vector3.Cross(Vertex2 - Vertex1, Vertex3 - Vertex1);
|
||||
var norm = Vector3.Normalize(dir);
|
||||
|
||||
vtx.nrm = norm;
|
||||
vtx2.nrm = norm;
|
||||
vtx3.nrm = norm;
|
||||
|
||||
KCLModel.Face face = new KCLModel.Face();
|
||||
|
||||
face.Text = f.CollisionFlags.ToString();
|
||||
|
||||
face.MaterialFlag = f.CollisionFlags;
|
||||
|
||||
Color color = SetMaterialColor(face);
|
||||
|
||||
|
||||
AllFlags.Add(face.MaterialFlag);
|
||||
|
||||
Vector3 ColorSet = new Vector3(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f);
|
||||
|
||||
vtx.col = new Vector3(ColorSet);
|
||||
vtx2.col = new Vector3(ColorSet);
|
||||
vtx3.col = new Vector3(ColorSet);
|
||||
|
||||
kclmodel.faces.Add(ft);
|
||||
kclmodel.faces.Add(ft + 1);
|
||||
kclmodel.faces.Add(ft + 2);
|
||||
|
||||
ft += 3;
|
||||
|
||||
kclmodel.vertices.Add(vtx);
|
||||
kclmodel.vertices.Add(vtx2);
|
||||
kclmodel.vertices.Add(vtx3);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
models.Add(kclmodel);
|
||||
|
||||
|
||||
|
||||
Nodes.Add(kclmodel);
|
||||
|
||||
CurModelIndx++;
|
||||
}*/
|
||||
}
|
||||
//Convert KCL lib vec3 to opentk one so i can use the cross and dot methods
|
||||
public static Vector3 Vec3F_To_Vec3(Syroot.Maths.Vector3F v)
|
||||
{
|
||||
return new Vector3(v.X, v.Y, v.Z);
|
||||
}
|
||||
}
|
||||
|
||||
//Convert KCL lib vec3 to opentk one so i can use the cross and dot methods
|
||||
public static Vector3 Vec3D_To_Vec3(System.Windows.Media.Media3D.Vector3D v)
|
||||
{
|
||||
return new Vector3((float)v.X, (float)v.Y, (float)v.Z);
|
||||
}
|
||||
public struct DisplayVertex
|
||||
{
|
||||
// Used for rendering.
|
||||
public Vector3 pos;
|
||||
public Vector3 nrm;
|
||||
public Vector3 tan;
|
||||
public Vector3 bit;
|
||||
public Vector2 uv;
|
||||
public Vector4 col;
|
||||
public Vector4 node;
|
||||
public Vector4 weight;
|
||||
public Vector2 uv2;
|
||||
public Vector2 uv3;
|
||||
public Vector3 pos1;
|
||||
public Vector3 pos2;
|
||||
public Vector3 col;
|
||||
|
||||
public static int Size = 4 * (3 + 3 + 3 + 3 + 2 + 4 + 4 + 4 + 2 + 2 + 3 + 3);
|
||||
public static int Size = 4 * (3 + 3 + 3);
|
||||
}
|
||||
public class KCLModel : STGenericObject
|
||||
{
|
||||
public KCLModel()
|
||||
{
|
||||
ImageKey = "mesh";
|
||||
SelectedImageKey = "mesh";
|
||||
|
||||
Checked = true;
|
||||
}
|
||||
|
||||
public int[] display;
|
||||
public int Offset; // For Rendering
|
||||
|
||||
public int strip = 0x40;
|
||||
public int displayFaceSize = 0;
|
||||
|
||||
public class Face : TreeNode
|
||||
{
|
||||
public int MaterialFlag = 0;
|
||||
|
||||
}
|
||||
|
||||
public List<DisplayVertex> CreateDisplayVertices()
|
||||
{
|
||||
// rearrange faces
|
||||
@ -466,7 +548,7 @@ namespace FirstPlugin
|
||||
{
|
||||
pos = v.pos,
|
||||
nrm = v.nrm,
|
||||
col = v.col,
|
||||
col = v.col.Xyz,
|
||||
};
|
||||
|
||||
displayVertList.Add(displayVert);
|
||||
|
@ -127,12 +127,12 @@ namespace FirstPlugin
|
||||
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
||||
public byte[] Data { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public TreeNode EditorRoot { get; set; }
|
||||
public TreeNodeFile EditorRoot { get; set; }
|
||||
public bool IsActive { get; set; } = false;
|
||||
public bool UseEditMenu { get; set; } = false;
|
||||
public IFileFormat ArchiveFile { get; set; }
|
||||
public int Alignment { get; set; } = 0;
|
||||
public string FilePath { get; set; }
|
||||
public IFileInfo IFileInfo { get; set; }
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
@ -144,7 +144,7 @@ namespace FirstPlugin
|
||||
}
|
||||
class MenuExt : IFileMenuExtension
|
||||
{
|
||||
public ToolStripItemDark[] NewFileMenuExtensions => newFileExt;
|
||||
public ToolStripItemDark[] NewFileMenuExtensions => null;
|
||||
public ToolStripItemDark[] ToolsMenuExtensions => null;
|
||||
public ToolStripItemDark[] TitleBarExtensions => null;
|
||||
public ToolStripItemDark[] CompressionMenuExtensions => null;
|
||||
@ -165,7 +165,7 @@ namespace FirstPlugin
|
||||
UseEditMenu = true;
|
||||
CanSave = true;
|
||||
|
||||
bntx = new BinaryTextureContainer(Data, FileName);
|
||||
bntx = new BinaryTextureContainer(Data, FileName, "", this);
|
||||
EditorRoot = bntx;
|
||||
}
|
||||
public void Unload()
|
||||
@ -186,7 +186,7 @@ namespace FirstPlugin
|
||||
}
|
||||
}
|
||||
|
||||
public class BinaryTextureContainer : TreeNodeCustom
|
||||
public class BinaryTextureContainer : TreeNodeFile
|
||||
{
|
||||
public Dictionary<string, TextureData> Textures;
|
||||
|
||||
@ -201,7 +201,7 @@ namespace FirstPlugin
|
||||
SelectedImageKey = "bntx";
|
||||
}
|
||||
|
||||
public BinaryTextureContainer(byte[] data, string Name = "", string FileName = "")
|
||||
public BinaryTextureContainer(byte[] data, string Name = "", string FileName = "", IFileFormat handler = null)
|
||||
{
|
||||
if (data.Length == 0)
|
||||
data = CreateNewBNTX(Name);
|
||||
@ -260,7 +260,6 @@ namespace FirstPlugin
|
||||
Textures = new Dictionary<string, TextureData>();
|
||||
|
||||
Data = data;
|
||||
|
||||
BinaryTexFile = new BntxFile(new MemoryStream(Data));
|
||||
Text = BinaryTexFile.Name;
|
||||
|
||||
@ -305,15 +304,19 @@ namespace FirstPlugin
|
||||
public void ImportTexture()
|
||||
{
|
||||
OpenFileDialog ofd = new OpenFileDialog();
|
||||
// ofd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" +
|
||||
ofd.Filter = "Supported Formats|*.bftex;*.dds;|" +
|
||||
"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.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.Filter = "Supported Formats|*.bftex;*.dds|" +
|
||||
"Binary Texture |*.bftex|" +
|
||||
"Microsoft DDS |*.dds|" +
|
||||
"All files(*.*)|*.*";
|
||||
|
||||
ofd.DefaultExt = "bftex";
|
||||
ofd.Multiselect = true;
|
||||
|
||||
@ -325,6 +328,8 @@ namespace FirstPlugin
|
||||
foreach (string name in ofd.FileNames)
|
||||
{
|
||||
string ext = Path.GetExtension(name);
|
||||
ext = ext.ToLower();
|
||||
|
||||
if (ext == ".dds" || ext == ".bftex")
|
||||
{
|
||||
AddTexture(name);
|
||||
@ -445,6 +450,8 @@ namespace FirstPlugin
|
||||
var importer = new TextureImporterSettings();
|
||||
|
||||
string ext = Path.GetExtension(name);
|
||||
ext = ext.ToLower();
|
||||
|
||||
switch (ext)
|
||||
{
|
||||
case ".bftex":
|
||||
@ -467,6 +474,8 @@ namespace FirstPlugin
|
||||
|
||||
TextureData texData = null;
|
||||
string ext = Path.GetExtension(name);
|
||||
ext = ext.ToLower();
|
||||
|
||||
switch (ext)
|
||||
{
|
||||
case ".bftex":
|
||||
@ -627,7 +636,7 @@ namespace FirstPlugin
|
||||
{
|
||||
public Texture Texture;
|
||||
public BntxFile bntxFile;
|
||||
public List<byte[]> mipmaps = new List<byte[]>();
|
||||
public List<List<byte[]>> mipmaps = new List<List<byte[]>>();
|
||||
public BRTI_Texture renderedGLTex = new BRTI_Texture();
|
||||
|
||||
BNTXEditor BNTXEditor;
|
||||
@ -723,7 +732,7 @@ namespace FirstPlugin
|
||||
throw new Exception("No texture data found");
|
||||
}
|
||||
|
||||
renderedGLTex.data = mipmaps[0];
|
||||
renderedGLTex.data = mipmaps[0][0];
|
||||
renderedGLTex.width = (int)Texture.Width;
|
||||
renderedGLTex.height = (int)Texture.Height;
|
||||
|
||||
@ -757,7 +766,7 @@ namespace FirstPlugin
|
||||
renderedGLTex.type = PixelInternalFormat.CompressedRgRgtc2;
|
||||
break;
|
||||
case SurfaceFormat.BC5_SNORM:
|
||||
renderedGLTex.data = DDS_Decompress.DecompressBC5(mipmaps[0], (int)Texture.Width, (int)Texture.Height, true, true);
|
||||
renderedGLTex.data = DDS_Decompress.DecompressBC5(mipmaps[0][0], (int)Texture.Width, (int)Texture.Height, true, true);
|
||||
renderedGLTex.type = PixelInternalFormat.Rgba;
|
||||
renderedGLTex.utype = OpenTK.Graphics.OpenGL.PixelFormat.Rgba;
|
||||
break;
|
||||
@ -912,15 +921,19 @@ namespace FirstPlugin
|
||||
private void Replace(object sender, EventArgs args)
|
||||
{
|
||||
OpenFileDialog ofd = new OpenFileDialog();
|
||||
// ofd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" +
|
||||
ofd.Filter = "Supported Formats|*.bftex;*.dds;|" +
|
||||
"Binary Texture |*.bftex|" +
|
||||
/* 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(*.*)|*.*";
|
||||
"Portable Network Graphics |*.png|" +
|
||||
"Joint Photographic Experts Group |*.jpg|" +
|
||||
"Bitmap Image |*.bmp|" +
|
||||
"Tagged Image File Format |*.tiff|" +
|
||||
"All files(*.*)|*.*";*/
|
||||
|
||||
ofd.Filter = "Supported Formats|*.bftex;*.dds|" +
|
||||
"Binary Texture |*.bftex|" +
|
||||
"Microsoft DDS |*.dds|" +
|
||||
"All files(*.*)|*.*";
|
||||
|
||||
ofd.Multiselect = false;
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
@ -931,6 +944,8 @@ namespace FirstPlugin
|
||||
public void Replace(string FileName)
|
||||
{
|
||||
string ext = Path.GetExtension(FileName);
|
||||
ext = ext.ToLower();
|
||||
|
||||
switch (ext)
|
||||
{
|
||||
case ".bftex":
|
||||
@ -982,9 +997,12 @@ namespace FirstPlugin
|
||||
Export(sfd.FileName);
|
||||
}
|
||||
}
|
||||
public void Export(string 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":
|
||||
@ -998,9 +1016,9 @@ namespace FirstPlugin
|
||||
break;
|
||||
}
|
||||
}
|
||||
internal void SaveBitMap(string FileName)
|
||||
internal void SaveBitMap(string FileName, int SurfaceLevel = 0, int MipLevel = 0)
|
||||
{
|
||||
Bitmap bitMap = DisplayTexture();
|
||||
Bitmap bitMap = DisplayTexture(MipLevel, SurfaceLevel);
|
||||
|
||||
bitMap.Save(FileName);
|
||||
}
|
||||
@ -1091,31 +1109,39 @@ namespace FirstPlugin
|
||||
uint blkHeight = blk_dim & 0xF;
|
||||
|
||||
int linesPerBlockHeight = (1 << (int)tex.BlockHeightLog2) * 8;
|
||||
int blockHeightShift = 0;
|
||||
|
||||
uint bpp = Formats.bpps((uint)((int)tex.Format >> 8));
|
||||
|
||||
for (int mipLevel = 0; mipLevel < tex.TextureData.Length; mipLevel++)
|
||||
for (int arrayLevel = 0; arrayLevel < tex.ArrayLength; arrayLevel++)
|
||||
{
|
||||
uint width = (uint)Math.Max(1, tex.Width >> mipLevel);
|
||||
uint height = (uint)Math.Max(1, tex.Height >> mipLevel);
|
||||
int blockHeightShift = 0;
|
||||
|
||||
uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp;
|
||||
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);
|
||||
|
||||
if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight)
|
||||
blockHeightShift += 1;
|
||||
uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp;
|
||||
|
||||
byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, (uint)tex.TileMode, (int)Math.Max(0, tex.BlockHeightLog2 - blockHeightShift), tex.TextureData[mipLevel]);
|
||||
//Create a copy and use that to remove uneeded data
|
||||
byte[] result_ = new byte[size];
|
||||
Array.Copy(result, 0, result_, 0, size);
|
||||
if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight)
|
||||
blockHeightShift += 1;
|
||||
|
||||
mipmaps.Add(result_);
|
||||
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;
|
||||
}
|
||||
|
||||
public Bitmap DisplayTexture(int DisplayMipIndex = 0)
|
||||
public Bitmap DisplayTexture(int DisplayMipIndex = 0, int ArrayIndex = 0)
|
||||
{
|
||||
LoadTexture(Texture);
|
||||
|
||||
@ -1127,7 +1153,7 @@ namespace FirstPlugin
|
||||
uint width = (uint)Math.Max(1, Texture.Width >> DisplayMipIndex);
|
||||
uint height = (uint)Math.Max(1, Texture.Height >> DisplayMipIndex);
|
||||
|
||||
byte[] data = mipmaps[DisplayMipIndex];
|
||||
byte[] data = mipmaps[ArrayIndex][DisplayMipIndex];
|
||||
|
||||
return DecodeBlock(data, width, height, Texture.Format);
|
||||
}
|
||||
|
546
Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs
Normal file
546
Switch_FileFormatsMain/FileFormats/Texture/FTEX.cs
Normal file
@ -0,0 +1,546 @@
|
||||
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 = "FTEXCONT";
|
||||
|
||||
ContextMenu = new ContextMenu();
|
||||
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 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();
|
||||
GX2CompSel ChannelRed;
|
||||
GX2CompSel ChannelBlue;
|
||||
GX2CompSel ChannelGreen;
|
||||
GX2CompSel ChannelAlpha;
|
||||
|
||||
public FTEX()
|
||||
{
|
||||
ContextMenu = new ContextMenu();
|
||||
MenuItem export = new MenuItem("Export");
|
||||
ContextMenu.MenuItems.Add(export);
|
||||
export.Click += Export;
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
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;
|
||||
|
||||
ChannelRed = tex.CompSelR;
|
||||
ChannelGreen = tex.CompSelG;
|
||||
ChannelBlue = tex.CompSelB;
|
||||
ChannelAlpha = tex.CompSelA;
|
||||
|
||||
renderedTex.width = (int)tex.Width;
|
||||
renderedTex.height = (int)tex.Height;
|
||||
format = (int)tex.Format;
|
||||
int swizzle = (int)tex.Swizzle;
|
||||
int pitch = (int)tex.Pitch;
|
||||
renderedTex.data = GTX.swizzleBC(tex.Data, renderedTex.width, renderedTex.height, format, (int)tex.TileMode, pitch, swizzle);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
bool IsDX10 = false;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_UNORM):
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_SRGB):
|
||||
dds.header.ddspf.fourCC = "DXT1";
|
||||
break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_UNORM):
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_SRGB):
|
||||
dds.header.ddspf.fourCC = "DXT3";
|
||||
break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_UNORM):
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_SRGB):
|
||||
dds.header.ddspf.fourCC = "DXT5";
|
||||
break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_UNORM):
|
||||
IsDX10 = true;
|
||||
dds.DX10header = new DDS.DX10Header();
|
||||
dds.DX10header.DXGI_Format = DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM;
|
||||
break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_SNORM):
|
||||
IsDX10 = true;
|
||||
dds.DX10header = new DDS.DX10Header();
|
||||
dds.DX10header.DXGI_Format = DDS.DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM;
|
||||
break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_UNORM):
|
||||
IsDX10 = true;
|
||||
dds.DX10header = new DDS.DX10Header();
|
||||
dds.DX10header.DXGI_Format = DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM;
|
||||
break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_SNORM):
|
||||
IsDX10 = true;
|
||||
dds.DX10header = new DDS.DX10Header();
|
||||
dds.DX10header.DXGI_Format = DDS.DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Format {(GTX.GX2SurfaceFormat)format} not supported!");
|
||||
}
|
||||
|
||||
if (IsDX10)
|
||||
dds.header.ddspf.fourCC = "DX10";
|
||||
|
||||
dds.Save(dds, FileName, renderedTex.mipmaps, IsDX10);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
byte[] fixBC5 = DDS_Decompress.DecompressBC5(renderedTex.data, renderedTex.width, renderedTex.height, true, true);
|
||||
renderedTex.data = fixBC5;
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
foreach (Control control in FirstPlugin.MainF.Controls)
|
||||
{
|
||||
if (control is DockPanel)
|
||||
{
|
||||
if (FirstPlugin.DockedEditorS == null)
|
||||
{
|
||||
FirstPlugin.DockedEditorS = new DockContent();
|
||||
FirstPlugin.DockedEditorS.Show((DockPanel)control, PluginRuntime.FSHPDockState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!EditorIsActive(FirstPlugin.DockedEditorS))
|
||||
{
|
||||
FirstPlugin.DockedEditorS.Controls.Clear();
|
||||
|
||||
FTEXEditor FTEXEditor = new FTEXEditor();
|
||||
FTEXEditor.Text = Text;
|
||||
FTEXEditor.Dock = DockStyle.Fill;
|
||||
FTEXEditor.LoadPicture(DisplayTexture());
|
||||
FTEXEditor.LoadProperty(this);
|
||||
FirstPlugin.DockedEditorS.Controls.Add(FTEXEditor);
|
||||
}
|
||||
}
|
||||
public bool EditorIsActive(DockContent dock)
|
||||
{
|
||||
foreach (Control ctrl in dock.Controls)
|
||||
{
|
||||
if (ctrl is FTEXEditor)
|
||||
{
|
||||
dock.Text = Text;
|
||||
((FTEXEditor)ctrl).LoadPicture(DisplayTexture());
|
||||
((FTEXEditor)ctrl).LoadProperty(this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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[]>>();
|
||||
|
||||
public byte[] data
|
||||
{
|
||||
get
|
||||
{
|
||||
return mipmaps[0][0];
|
||||
}
|
||||
set
|
||||
{
|
||||
List<byte[]> mips = new List<byte[]>();
|
||||
mips.Add(value);
|
||||
mipmaps.Add(mips);
|
||||
}
|
||||
}
|
||||
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, format);
|
||||
}
|
||||
|
||||
public static Bitmap DecodeBlock(byte[] data, uint Width, uint Height, int Format)
|
||||
{
|
||||
Bitmap decomp;
|
||||
|
||||
switch (Format)
|
||||
{
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_UNORM):
|
||||
decomp = DDS_Decompress.DecompressBC1(data, (int)Width, (int)Height, false); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_SRGB):
|
||||
decomp = DDS_Decompress.DecompressBC1(data, (int)Width, (int)Height, true); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_UNORM):
|
||||
decomp = DDS_Decompress.DecompressBC3(data, (int)Width, (int)Height, false); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_SRGB):
|
||||
decomp = DDS_Decompress.DecompressBC3(data, (int)Width, (int)Height, true); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_UNORM):
|
||||
decomp = DDS_Decompress.DecompressBC4(data, (int)Width, (int)Height, false); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_SNORM):
|
||||
decomp = DDS_Decompress.DecompressBC4(data, (int)Width, (int)Height, true); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_UNORM):
|
||||
decomp = DDS_Decompress.DecompressBC5(data, (int)Width, (int)Height, false); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_SNORM):
|
||||
decomp = DDS_Decompress.DecompressBC5(data, (int)Width, (int)Height, true); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SNORM):
|
||||
decomp = DDS_PixelDecode.DecodeR8G8B8A8(data, (int)Width, (int)Height); break;
|
||||
case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_UINT):
|
||||
decomp = DDS_PixelDecode.DecodeR8G8B8A8(data, (int)Width, (int)Height); break;
|
||||
default:
|
||||
decomp = Properties.Resources.TextureError;
|
||||
Console.WriteLine($"Format {Format} not supported!");
|
||||
break;
|
||||
}
|
||||
return decomp;
|
||||
}
|
||||
|
||||
public Bitmap UpdateBitmap(Bitmap image)
|
||||
{
|
||||
return ColorComponentSelector(image, ChannelRed, ChannelGreen, ChannelBlue, ChannelAlpha);
|
||||
}
|
||||
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.One;
|
||||
if (R == GX2CompSel.Always1)
|
||||
color.CompRed = BitmapExtension.ColorSwapFilter.Red.Zero;
|
||||
|
||||
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.One;
|
||||
if (G == GX2CompSel.Always1)
|
||||
color.CompGreen = BitmapExtension.ColorSwapFilter.Green.Zero;
|
||||
|
||||
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.One;
|
||||
if (B == GX2CompSel.Always1)
|
||||
color.CompBlue = BitmapExtension.ColorSwapFilter.Blue.Zero;
|
||||
|
||||
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.One;
|
||||
if (A == GX2CompSel.Always1)
|
||||
color.CompAlpha = BitmapExtension.ColorSwapFilter.Alpha.Zero;
|
||||
|
||||
return BitmapExtension.SwapRGB(image, color);
|
||||
}
|
||||
}
|
||||
}
|
1138
Switch_FileFormatsMain/FileFormats/Texture/GTX.cs
Normal file
1138
Switch_FileFormatsMain/FileFormats/Texture/GTX.cs
Normal file
File diff suppressed because it is too large
Load Diff
13
Switch_FileFormatsMain/FileFormats/Texture/TexConv.cs
Normal file
13
Switch_FileFormatsMain/FileFormats/Texture/TexConv.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
class TexConv
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -20,11 +20,12 @@ namespace FirstPlugin
|
||||
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
||||
public byte[] Data { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public TreeNode EditorRoot { 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user