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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.IO;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Switch_Toolbox;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Switch_Toolbox.Library;
|
using Switch_Toolbox.Library;
|
||||||
using KCLExt;
|
|
||||||
using SFGraphics.GLObjects.Shaders;
|
using SFGraphics.GLObjects.Shaders;
|
||||||
using Smash_Forge.Rendering;
|
using Smash_Forge.Rendering;
|
||||||
using GL_Core.Interfaces;
|
using GL_Core.Interfaces;
|
||||||
@ -15,6 +11,8 @@ using OpenTK;
|
|||||||
using Switch_Toolbox.Library.Rendering;
|
using Switch_Toolbox.Library.Rendering;
|
||||||
using WeifenLuo.WinFormsUI.Docking;
|
using WeifenLuo.WinFormsUI.Docking;
|
||||||
using GL_Core;
|
using GL_Core;
|
||||||
|
using System.Drawing;
|
||||||
|
using Switch_Toolbox.Library.IO;
|
||||||
|
|
||||||
namespace FirstPlugin
|
namespace FirstPlugin
|
||||||
{
|
{
|
||||||
@ -29,11 +27,12 @@ namespace FirstPlugin
|
|||||||
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
public string FileName { 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 IsActive { get; set; } = false;
|
||||||
public bool UseEditMenu { get; set; } = false;
|
public bool UseEditMenu { get; set; } = false;
|
||||||
public int Alignment { get; set; } = 0;
|
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; set; }
|
||||||
|
public IFileInfo IFileInfo { get; set; }
|
||||||
|
|
||||||
public Type[] Types
|
public Type[] Types
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -46,7 +45,8 @@ namespace FirstPlugin
|
|||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
IsActive = true;
|
IsActive = true;
|
||||||
EditorRoot = new KCLRoot(FileName);
|
EditorRoot = new KCLRoot(FileName, this);
|
||||||
|
IFileInfo = new IFileInfo();
|
||||||
}
|
}
|
||||||
public void Unload()
|
public void Unload()
|
||||||
{
|
{
|
||||||
@ -54,7 +54,34 @@ namespace FirstPlugin
|
|||||||
}
|
}
|
||||||
public byte[] Save()
|
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
|
public enum GameSet : ushort
|
||||||
@ -117,23 +144,152 @@ namespace FirstPlugin
|
|||||||
BoostTrick = 8202,
|
BoostTrick = 8202,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Shader shader = null;
|
public class KCLRoot : TreeNodeFile
|
||||||
|
|
||||||
public class KCLRoot : TreeNodeCustom
|
|
||||||
{
|
{
|
||||||
public KCLRoot(string Name)
|
public KCLRoot(string Name, IFileFormat handler)
|
||||||
{
|
{
|
||||||
Text = Name;
|
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;
|
KCLRendering Renderer;
|
||||||
public override void OnClick(TreeView treeView)
|
public override void OnClick(TreeView treeView)
|
||||||
{
|
{
|
||||||
//If has models
|
Renderer.LoadViewport();
|
||||||
if (Nodes[0].Nodes.Count > 0)
|
Renderer.UpdateVertexData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarioKart.MK7.KCL kcl = null;
|
||||||
|
public void Read(byte[] file_data)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Renderer.LoadViewport();
|
kcl = new MarioKart.MK7.KCL(file_data, Syroot.BinaryData.ByteOrder.LittleEndian);
|
||||||
Renderer.UpdateVertexData();
|
}
|
||||||
|
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
|
//Set the game's material list
|
||||||
public GameSet GameMaterialSet = GameSet.MarioKart8D;
|
public GameSet GameMaterialSet = GameSet.MarioKart8D;
|
||||||
public List<KCLModel> models = new List<KCLModel>();
|
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 vbo_position);
|
||||||
GL.GenBuffers(1, out ibo_elements);
|
GL.GenBuffers(1, out ibo_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Destroy()
|
||||||
|
{
|
||||||
|
GL.DeleteBuffer(vbo_position);
|
||||||
|
GL.DeleteBuffer(ibo_elements);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateVertexData()
|
public void UpdateVertexData()
|
||||||
{
|
{
|
||||||
|
if (OpenTKSharedResources.SetupStatus == OpenTKSharedResources.SharedResourceStatus.Unitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
DisplayVertex[] Vertices;
|
DisplayVertex[] Vertices;
|
||||||
int[] Faces;
|
int[] Faces;
|
||||||
|
|
||||||
@ -169,8 +335,6 @@ namespace FirstPlugin
|
|||||||
List<DisplayVertex> pv = m.CreateDisplayVertices();
|
List<DisplayVertex> pv = m.CreateDisplayVertices();
|
||||||
Vs.AddRange(pv);
|
Vs.AddRange(pv);
|
||||||
|
|
||||||
Console.WriteLine(m.displayFaceSize);
|
|
||||||
|
|
||||||
for (int i = 0; i < m.displayFaceSize; i++)
|
for (int i = 0; i < m.displayFaceSize; i++)
|
||||||
{
|
{
|
||||||
Ds.Add(m.display[i] + voffset);
|
Ds.Add(m.display[i] + voffset);
|
||||||
@ -189,6 +353,8 @@ namespace FirstPlugin
|
|||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
|
||||||
GL.BufferData<int>(BufferTarget.ElementArrayBuffer, (IntPtr)(Faces.Length * sizeof(int)), Faces, BufferUsageHint.StaticDraw);
|
GL.BufferData<int>(BufferTarget.ElementArrayBuffer, (IntPtr)(Faces.Length * sizeof(int)), Faces, BufferUsageHint.StaticDraw);
|
||||||
|
|
||||||
|
Viewport.Instance.UpdateViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
string FileName;
|
string FileName;
|
||||||
@ -226,9 +392,16 @@ namespace FirstPlugin
|
|||||||
}
|
}
|
||||||
public override void Draw(GL_ControlModern control)
|
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.UseProgram();
|
||||||
|
|
||||||
shader.EnableVertexAttributes();
|
shader.EnableVertexAttributes();
|
||||||
SetRenderSettings(shader);
|
SetRenderSettings(shader);
|
||||||
|
|
||||||
@ -237,10 +410,13 @@ namespace FirstPlugin
|
|||||||
Matrix4 camMat = previewScale * control.mtxCam * control.mtxProj;
|
Matrix4 camMat = previewScale * control.mtxCam * control.mtxProj;
|
||||||
|
|
||||||
shader.SetVector3("difLightDirection", Vector3.TransformNormal(new Vector3(0f, 0f, -1f), camMat.Inverted()).Normalized());
|
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();
|
shader.EnableVertexAttributes();
|
||||||
SetRenderSettings(shader);
|
SetRenderSettings(shader);
|
||||||
|
|
||||||
shader.SetMatrix4x4("modelview", ref camMat);
|
shader.SetMatrix4x4("mvpMatrix", ref camMat);
|
||||||
|
|
||||||
foreach (KCLModel mdl in models)
|
foreach (KCLModel mdl in models)
|
||||||
{
|
{
|
||||||
@ -318,138 +494,44 @@ namespace FirstPlugin
|
|||||||
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
||||||
shader.SetInt("colorOverride", 0);
|
shader.SetInt("colorOverride", 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public MarioKart.MK7.KCL kcl = null;
|
|
||||||
public void Read(byte[] file_data)
|
//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)
|
||||||
try
|
{
|
||||||
{
|
return new Vector3((float)v.X, (float)v.Y, (float)v.Z);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public struct DisplayVertex
|
public struct DisplayVertex
|
||||||
{
|
{
|
||||||
// Used for rendering.
|
// Used for rendering.
|
||||||
public Vector3 pos;
|
public Vector3 pos;
|
||||||
public Vector3 nrm;
|
public Vector3 nrm;
|
||||||
public Vector3 tan;
|
public Vector3 col;
|
||||||
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 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 class KCLModel : STGenericObject
|
||||||
{
|
{
|
||||||
|
public KCLModel()
|
||||||
|
{
|
||||||
|
ImageKey = "mesh";
|
||||||
|
SelectedImageKey = "mesh";
|
||||||
|
|
||||||
|
Checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
public int[] display;
|
public int[] display;
|
||||||
public int Offset; // For Rendering
|
public int Offset; // For Rendering
|
||||||
|
|
||||||
public int strip = 0x40;
|
public int strip = 0x40;
|
||||||
public int displayFaceSize = 0;
|
public int displayFaceSize = 0;
|
||||||
|
|
||||||
|
public class Face : TreeNode
|
||||||
|
{
|
||||||
|
public int MaterialFlag = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public List<DisplayVertex> CreateDisplayVertices()
|
public List<DisplayVertex> CreateDisplayVertices()
|
||||||
{
|
{
|
||||||
// rearrange faces
|
// rearrange faces
|
||||||
@ -466,7 +548,7 @@ namespace FirstPlugin
|
|||||||
{
|
{
|
||||||
pos = v.pos,
|
pos = v.pos,
|
||||||
nrm = v.nrm,
|
nrm = v.nrm,
|
||||||
col = v.col,
|
col = v.col.Xyz,
|
||||||
};
|
};
|
||||||
|
|
||||||
displayVertList.Add(displayVert);
|
displayVertList.Add(displayVert);
|
||||||
|
@ -127,12 +127,12 @@ namespace FirstPlugin
|
|||||||
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
public CompressionType CompressionType { get; set; } = CompressionType.None;
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
public string FileName { 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 IsActive { get; set; } = false;
|
||||||
public bool UseEditMenu { get; set; } = false;
|
public bool UseEditMenu { get; set; } = false;
|
||||||
public IFileFormat ArchiveFile { get; set; }
|
|
||||||
public int Alignment { get; set; } = 0;
|
public int Alignment { get; set; } = 0;
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; set; }
|
||||||
|
public IFileInfo IFileInfo { get; set; }
|
||||||
public Type[] Types
|
public Type[] Types
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -144,7 +144,7 @@ namespace FirstPlugin
|
|||||||
}
|
}
|
||||||
class MenuExt : IFileMenuExtension
|
class MenuExt : IFileMenuExtension
|
||||||
{
|
{
|
||||||
public ToolStripItemDark[] NewFileMenuExtensions => newFileExt;
|
public ToolStripItemDark[] NewFileMenuExtensions => null;
|
||||||
public ToolStripItemDark[] ToolsMenuExtensions => null;
|
public ToolStripItemDark[] ToolsMenuExtensions => null;
|
||||||
public ToolStripItemDark[] TitleBarExtensions => null;
|
public ToolStripItemDark[] TitleBarExtensions => null;
|
||||||
public ToolStripItemDark[] CompressionMenuExtensions => null;
|
public ToolStripItemDark[] CompressionMenuExtensions => null;
|
||||||
@ -165,7 +165,7 @@ namespace FirstPlugin
|
|||||||
UseEditMenu = true;
|
UseEditMenu = true;
|
||||||
CanSave = true;
|
CanSave = true;
|
||||||
|
|
||||||
bntx = new BinaryTextureContainer(Data, FileName);
|
bntx = new BinaryTextureContainer(Data, FileName, "", this);
|
||||||
EditorRoot = bntx;
|
EditorRoot = bntx;
|
||||||
}
|
}
|
||||||
public void Unload()
|
public void Unload()
|
||||||
@ -186,7 +186,7 @@ namespace FirstPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BinaryTextureContainer : TreeNodeCustom
|
public class BinaryTextureContainer : TreeNodeFile
|
||||||
{
|
{
|
||||||
public Dictionary<string, TextureData> Textures;
|
public Dictionary<string, TextureData> Textures;
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ namespace FirstPlugin
|
|||||||
SelectedImageKey = "bntx";
|
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)
|
if (data.Length == 0)
|
||||||
data = CreateNewBNTX(Name);
|
data = CreateNewBNTX(Name);
|
||||||
@ -260,7 +260,6 @@ namespace FirstPlugin
|
|||||||
Textures = new Dictionary<string, TextureData>();
|
Textures = new Dictionary<string, TextureData>();
|
||||||
|
|
||||||
Data = data;
|
Data = data;
|
||||||
|
|
||||||
BinaryTexFile = new BntxFile(new MemoryStream(Data));
|
BinaryTexFile = new BntxFile(new MemoryStream(Data));
|
||||||
Text = BinaryTexFile.Name;
|
Text = BinaryTexFile.Name;
|
||||||
|
|
||||||
@ -305,15 +304,19 @@ namespace FirstPlugin
|
|||||||
public void ImportTexture()
|
public void ImportTexture()
|
||||||
{
|
{
|
||||||
OpenFileDialog ofd = new OpenFileDialog();
|
OpenFileDialog ofd = new OpenFileDialog();
|
||||||
// ofd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" +
|
/* ofd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" +
|
||||||
ofd.Filter = "Supported Formats|*.bftex;*.dds;|" +
|
"Binary Texture |*.bftex|" +
|
||||||
"Binary Texture |*.bftex|" +
|
"Microsoft DDS |*.dds|" +
|
||||||
"Microsoft DDS |*.dds|" +
|
"Portable Network Graphics |*.png|" +
|
||||||
/* "Portable Network Graphics |*.png|" +
|
"Joint Photographic Experts Group |*.jpg|" +
|
||||||
"Joint Photographic Experts Group |*.jpg|" +
|
"Bitmap Image |*.bmp|" +
|
||||||
"Bitmap Image |*.bmp|" +
|
"Tagged Image File Format |*.tiff|" +
|
||||||
"Tagged Image File Format |*.tiff|" */
|
"All files(*.*)|*.*";*/
|
||||||
"All files(*.*)|*.*";
|
ofd.Filter = "Supported Formats|*.bftex;*.dds|" +
|
||||||
|
"Binary Texture |*.bftex|" +
|
||||||
|
"Microsoft DDS |*.dds|" +
|
||||||
|
"All files(*.*)|*.*";
|
||||||
|
|
||||||
ofd.DefaultExt = "bftex";
|
ofd.DefaultExt = "bftex";
|
||||||
ofd.Multiselect = true;
|
ofd.Multiselect = true;
|
||||||
|
|
||||||
@ -325,6 +328,8 @@ namespace FirstPlugin
|
|||||||
foreach (string name in ofd.FileNames)
|
foreach (string name in ofd.FileNames)
|
||||||
{
|
{
|
||||||
string ext = Path.GetExtension(name);
|
string ext = Path.GetExtension(name);
|
||||||
|
ext = ext.ToLower();
|
||||||
|
|
||||||
if (ext == ".dds" || ext == ".bftex")
|
if (ext == ".dds" || ext == ".bftex")
|
||||||
{
|
{
|
||||||
AddTexture(name);
|
AddTexture(name);
|
||||||
@ -445,6 +450,8 @@ namespace FirstPlugin
|
|||||||
var importer = new TextureImporterSettings();
|
var importer = new TextureImporterSettings();
|
||||||
|
|
||||||
string ext = Path.GetExtension(name);
|
string ext = Path.GetExtension(name);
|
||||||
|
ext = ext.ToLower();
|
||||||
|
|
||||||
switch (ext)
|
switch (ext)
|
||||||
{
|
{
|
||||||
case ".bftex":
|
case ".bftex":
|
||||||
@ -467,6 +474,8 @@ namespace FirstPlugin
|
|||||||
|
|
||||||
TextureData texData = null;
|
TextureData texData = null;
|
||||||
string ext = Path.GetExtension(name);
|
string ext = Path.GetExtension(name);
|
||||||
|
ext = ext.ToLower();
|
||||||
|
|
||||||
switch (ext)
|
switch (ext)
|
||||||
{
|
{
|
||||||
case ".bftex":
|
case ".bftex":
|
||||||
@ -627,7 +636,7 @@ namespace FirstPlugin
|
|||||||
{
|
{
|
||||||
public Texture Texture;
|
public Texture Texture;
|
||||||
public BntxFile bntxFile;
|
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();
|
public BRTI_Texture renderedGLTex = new BRTI_Texture();
|
||||||
|
|
||||||
BNTXEditor BNTXEditor;
|
BNTXEditor BNTXEditor;
|
||||||
@ -723,7 +732,7 @@ namespace FirstPlugin
|
|||||||
throw new Exception("No texture data found");
|
throw new Exception("No texture data found");
|
||||||
}
|
}
|
||||||
|
|
||||||
renderedGLTex.data = mipmaps[0];
|
renderedGLTex.data = mipmaps[0][0];
|
||||||
renderedGLTex.width = (int)Texture.Width;
|
renderedGLTex.width = (int)Texture.Width;
|
||||||
renderedGLTex.height = (int)Texture.Height;
|
renderedGLTex.height = (int)Texture.Height;
|
||||||
|
|
||||||
@ -757,7 +766,7 @@ namespace FirstPlugin
|
|||||||
renderedGLTex.type = PixelInternalFormat.CompressedRgRgtc2;
|
renderedGLTex.type = PixelInternalFormat.CompressedRgRgtc2;
|
||||||
break;
|
break;
|
||||||
case SurfaceFormat.BC5_SNORM:
|
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.type = PixelInternalFormat.Rgba;
|
||||||
renderedGLTex.utype = OpenTK.Graphics.OpenGL.PixelFormat.Rgba;
|
renderedGLTex.utype = OpenTK.Graphics.OpenGL.PixelFormat.Rgba;
|
||||||
break;
|
break;
|
||||||
@ -912,15 +921,19 @@ namespace FirstPlugin
|
|||||||
private void Replace(object sender, EventArgs args)
|
private void Replace(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
OpenFileDialog ofd = new OpenFileDialog();
|
OpenFileDialog ofd = new OpenFileDialog();
|
||||||
// ofd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" +
|
/* ofd.Filter = "Supported Formats|*.bftex;*.dds; *.png;*.tga;*.jpg;*.tiff|" +
|
||||||
ofd.Filter = "Supported Formats|*.bftex;*.dds;|" +
|
"Binary Texture |*.bftex|" +
|
||||||
"Binary Texture |*.bftex|" +
|
|
||||||
"Microsoft DDS |*.dds|" +
|
"Microsoft DDS |*.dds|" +
|
||||||
/* "Portable Network Graphics |*.png|" +
|
"Portable Network Graphics |*.png|" +
|
||||||
"Joint Photographic Experts Group |*.jpg|" +
|
"Joint Photographic Experts Group |*.jpg|" +
|
||||||
"Bitmap Image |*.bmp|" +
|
"Bitmap Image |*.bmp|" +
|
||||||
"Tagged Image File Format |*.tiff|" */
|
"Tagged Image File Format |*.tiff|" +
|
||||||
"All files(*.*)|*.*";
|
"All files(*.*)|*.*";*/
|
||||||
|
|
||||||
|
ofd.Filter = "Supported Formats|*.bftex;*.dds|" +
|
||||||
|
"Binary Texture |*.bftex|" +
|
||||||
|
"Microsoft DDS |*.dds|" +
|
||||||
|
"All files(*.*)|*.*";
|
||||||
|
|
||||||
ofd.Multiselect = false;
|
ofd.Multiselect = false;
|
||||||
if (ofd.ShowDialog() == DialogResult.OK)
|
if (ofd.ShowDialog() == DialogResult.OK)
|
||||||
@ -931,6 +944,8 @@ namespace FirstPlugin
|
|||||||
public void Replace(string FileName)
|
public void Replace(string FileName)
|
||||||
{
|
{
|
||||||
string ext = Path.GetExtension(FileName);
|
string ext = Path.GetExtension(FileName);
|
||||||
|
ext = ext.ToLower();
|
||||||
|
|
||||||
switch (ext)
|
switch (ext)
|
||||||
{
|
{
|
||||||
case ".bftex":
|
case ".bftex":
|
||||||
@ -982,9 +997,12 @@ namespace FirstPlugin
|
|||||||
Export(sfd.FileName);
|
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);
|
string ext = Path.GetExtension(FileName);
|
||||||
|
ext = ext.ToLower();
|
||||||
|
|
||||||
switch (ext)
|
switch (ext)
|
||||||
{
|
{
|
||||||
case ".bftex":
|
case ".bftex":
|
||||||
@ -998,9 +1016,9 @@ namespace FirstPlugin
|
|||||||
break;
|
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);
|
bitMap.Save(FileName);
|
||||||
}
|
}
|
||||||
@ -1091,31 +1109,39 @@ namespace FirstPlugin
|
|||||||
uint blkHeight = blk_dim & 0xF;
|
uint blkHeight = blk_dim & 0xF;
|
||||||
|
|
||||||
int linesPerBlockHeight = (1 << (int)tex.BlockHeightLog2) * 8;
|
int linesPerBlockHeight = (1 << (int)tex.BlockHeightLog2) * 8;
|
||||||
int blockHeightShift = 0;
|
|
||||||
|
|
||||||
uint bpp = Formats.bpps((uint)((int)tex.Format >> 8));
|
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);
|
int blockHeightShift = 0;
|
||||||
uint height = (uint)Math.Max(1, tex.Height >> mipLevel);
|
|
||||||
|
|
||||||
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)
|
uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp;
|
||||||
blockHeightShift += 1;
|
|
||||||
|
|
||||||
byte[] result = TegraX1Swizzle.deswizzle(width, height, blkWidth, blkHeight, target, bpp, (uint)tex.TileMode, (int)Math.Max(0, tex.BlockHeightLog2 - blockHeightShift), tex.TextureData[mipLevel]);
|
if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight)
|
||||||
//Create a copy and use that to remove uneeded data
|
blockHeightShift += 1;
|
||||||
byte[] result_ = new byte[size];
|
|
||||||
Array.Copy(result, 0, result_, 0, size);
|
|
||||||
|
|
||||||
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;
|
Texture = tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap DisplayTexture(int DisplayMipIndex = 0)
|
public Bitmap DisplayTexture(int DisplayMipIndex = 0, int ArrayIndex = 0)
|
||||||
{
|
{
|
||||||
LoadTexture(Texture);
|
LoadTexture(Texture);
|
||||||
|
|
||||||
@ -1127,7 +1153,7 @@ namespace FirstPlugin
|
|||||||
uint width = (uint)Math.Max(1, Texture.Width >> DisplayMipIndex);
|
uint width = (uint)Math.Max(1, Texture.Width >> DisplayMipIndex);
|
||||||
uint height = (uint)Math.Max(1, Texture.Height >> 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);
|
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 CompressionType CompressionType { get; set; } = CompressionType.None;
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
public string FileName { 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 IsActive { get; set; } = false;
|
||||||
public bool UseEditMenu { get; set; } = false;
|
public bool UseEditMenu { get; set; } = false;
|
||||||
public int Alignment { get; set; } = 0;
|
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; set; }
|
||||||
|
public IFileInfo IFileInfo { get; set; }
|
||||||
|
|
||||||
public Type[] Types
|
public Type[] Types
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
Loading…
x
Reference in New Issue
Block a user