1
0
mirror of synced 2024-12-01 10:37:25 +01:00
Switch-Toolbox/File_Format_Library/FileFormats/Effects/PCTL.cs

1355 lines
51 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using Toolbox.Library.IO;
using Toolbox.Library;
using System.IO;
using Syroot.BinaryData;
using System.Windows.Forms;
using Toolbox.Library.Forms;
using Bfres.Structs;
namespace FirstPlugin
{
public class PTCL : TreeNodeFile, IFileFormat
{
public FileType FileType { get; set; } = FileType.Effect;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Cafe Particle" };
public string[] Extension { get; set; } = new string[] { "*.ptcl", "*.sesetlist" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
{
if (reader.CheckSignature(4, "VFXB") ||
reader.CheckSignature(4, "SPBD") ||
reader.CheckSignature(4, "EFTF") ||
reader.CheckSignature(4, "EFTB"))
return true;
else
return false;
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public Header header;
public PTCL_WiiU.Header headerU;
public PTCL_3DS.Header header3DS;
public byte[] data;
bool IsWiiU = false;
bool Is3DS = false;
public void Load(Stream stream)
{
data = stream.ToArray();
Text = FileName;
CanSave = true;
using (var reader = new FileReader(stream))
{
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
string Signature = reader.ReadString(4, Encoding.ASCII);
byte VersionNum = reader.ReadByte();
if (VersionNum != 0 && Signature == "SPBD")
Is3DS = true;
reader.Position = 0;
if (Is3DS)
{
reader.ByteOrder = ByteOrder.LittleEndian;
header3DS = new PTCL_3DS.Header();
header3DS.Read(reader, this);
}
else if (Signature == "EFTF" || Signature == "SPBD")
{
IsWiiU = true;
headerU = new PTCL_WiiU.Header();
headerU.Read(reader, this);
}
else
{
header = new Header();
header.Read(reader, this);
}
}
ContextMenuStrip = new STContextMenuStrip();
ContextMenuStrip.Items.Add(new ToolStripMenuItem("Save", null, Save, Keys.Control | Keys.S));
}
public void Unload()
{
}
public void Save(System.IO.Stream stream)
{
if (Is3DS)
header3DS.Write(new FileWriter(stream), this);
else if (IsWiiU)
headerU.Write(new FileWriter(stream), this);
else
header.Write(new FileWriter(stream));
}
private void Save(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = Utils.GetAllFilters(typeof(PTCL));
sfd.FileName = FileName;
if (sfd.ShowDialog() == DialogResult.OK)
STFileSaver.SaveFileFormat(this, sfd.FileName);
}
public class WiiU
{
}
public static readonly uint NullOffset = 0xFFFFFFFF;
public class Header
{
public BNTX BinaryTextureFile = null;
public string Signature;
public ushort GraphicsAPIVersion;
public ushort VFXVersion;
public ushort ByteOrderMark;
public byte Alignment;
public byte TargetOffset;
public ushort Flag;
public ushort BlockOffset;
public uint DataAlignment;
//For saving
public List<SectionBase> Sections = new List<SectionBase>();
private string UnknownString;
public void Read(FileReader reader, PTCL ptcl)
{
uint Position = (uint)reader.Position; //Offsets are relative to this
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
Signature = reader.ReadString(4, Encoding.ASCII);
if (Signature == "EFTB")
{
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
reader.Seek(48, SeekOrigin.Begin);
}
else if (Signature == "VFXB")
{
uint padding = reader.ReadUInt32();
GraphicsAPIVersion = reader.ReadUInt16();
VFXVersion = reader.ReadUInt16();
ByteOrderMark = reader.ReadUInt16();
Alignment = reader.ReadByte();
TargetOffset = reader.ReadByte();
uint HeaderSize = reader.ReadUInt32();
Flag = reader.ReadUInt16();
BlockOffset = reader.ReadUInt16();
uint padding2 = reader.ReadUInt32();
uint FileSize = reader.ReadUInt32();
reader.Seek(Position + BlockOffset, SeekOrigin.Begin);
}
else
{
throw new Exception("Unknown ptcl format. Signature not valid " + Signature);
}
while (reader.Position < reader.BaseStream.Length)
{
SectionBase sectionBase = new SectionBase();
sectionBase.Read(reader, this);
Sections.Add(sectionBase);
ptcl.Nodes.Add(sectionBase);
if (sectionBase.NextSectionOffset == NullOffset)
break;
}
MapTextureIDs(ptcl);
reader.Dispose();
reader.Close();
}
private void MapTextureIDs(PTCL ptcl)
{
List<TextureDescriptor> texDescp = new List<TextureDescriptor>();
List<Emitter> emitters = new List<Emitter>();
BNTX bntx = ptcl.header.BinaryTextureFile;
List<TEXR> botwTex = new List<TEXR>(); //Used for BOTW
foreach (var node in TreeViewExtensions.Collect(ptcl.Nodes))
{
if (node is TextureDescriptor)
texDescp.Add((TextureDescriptor)node);
if (node is SectionBase && ((SectionBase)node).BinaryData is Emitter)
emitters.Add((Emitter)((SectionBase)node).BinaryData);
if (node is SectionBase && ((SectionBase)node).BinaryData is TEXR)
botwTex.Add((TEXR)((SectionBase)node).BinaryData);
}
int index = 0;
if (botwTex.Count > 0)
{
TextureFolder textureFolder = new TextureFolder("Textures");
ptcl.Nodes.Add(textureFolder);
List<TEXR> TextureList = new List<TEXR>();
foreach (var emitter in emitters)
{
foreach (TEXR tex in botwTex)
{
bool HasImage = TextureList.Any(item => item.data == tex.data);
if (!HasImage)
{
tex.Text = "Texture " + index++;
textureFolder.Nodes.Add(tex);
}
TextureList.Add(tex);
foreach (var sampler in emitter.Samplers)
{
if (sampler.TextureID == tex.TextureID)
{
emitter.DrawableTex.Add(tex);
}
}
}
}
TextureList.Clear();
}
if (bntx == null)
return;
foreach (var emitter in emitters)
{
foreach (var tex in texDescp)
{
foreach (var sampler in emitter.Samplers)
{
if (sampler.TextureID == tex.TextureID)
{
if (bntx.Textures.ContainsKey(tex.TexName))
{
emitter.DrawableTex.Add(bntx.Textures[tex.TexName]);
}
}
}
}
}
}
public class TextureFolder : TreeNodeCustom, IContextMenuNode, ITextureIconLoader
{
public TextureFolder(string text)
{
Text = text;
}
public ToolStripItem[] GetContextMenuItems()
{
return new ToolStripItem[]
{
new ToolStripMenuItem("Export All Textures", null, ExportAll, Keys.Control | Keys.A),
};
}
public List<STGenericTexture> IconTextureList
{
get
{
List<STGenericTexture> textures = new List<STGenericTexture>();
foreach (STGenericTexture node in Nodes)
textures.Add(node);
return textures;
}
set { }
}
private void ExportAll(object sender, EventArgs args)
{
List<string> Formats = new List<string>();
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;
BatchFormatExport form = new BatchFormatExport(Formats);
if (form.ShowDialog() == DialogResult.OK)
{
foreach (STGenericTexture tex in Nodes)
{
if (form.Index == 0)
tex.SaveDDS(folderPath + '\\' + tex.Text + ".dds");
else if (form.Index == 1)
tex.SaveBitMap(folderPath + '\\' + tex.Text + ".png");
else if (form.Index == 2)
tex.SaveBitMap(folderPath + '\\' + tex.Text + ".jpg");
else if (form.Index == 3)
tex.SaveBitMap(folderPath + '\\' + tex.Text + ".bmp");
else if (form.Index == 4)
tex.SaveBitMap(folderPath + '\\' + tex.Text + ".tiff");
}
}
}
}
}
private TreeNodeFile GetMagic(SectionBase section)
{
TreeNodeFile node = new TreeNodeFile();
node.Text = section.Signature;
foreach (var child in section.ChildSections)
{
node.Nodes.Add(GetMagic(child));
}
return node;
}
public void Write(FileWriter writer)
{
writer.WriteSignature("VFXB");
writer.Write(0x20202020);
writer.Write(GraphicsAPIVersion);
writer.Write(VFXVersion);
writer.Write(ByteOrderMark);
writer.Write(Alignment);
writer.Write(TargetOffset);
writer.Write(32);
writer.Write(Flag);
writer.Write(BlockOffset);
writer.Write(0);
long _ofsFileSize = writer.Position;
writer.Write(0);
writer.Seek(BlockOffset, SeekOrigin.Begin);
foreach (var section in Sections)
{
writer.Align(8);
section.Write(writer, this);
}
using (writer.TemporarySeek(_ofsFileSize, SeekOrigin.Begin))
{
writer.Write(writer.BaseStream.Length);
}
writer.Flush();
writer.Close();
writer.Dispose();
}
}
static bool ChildHasBinary = false;
// public static readonly uint NullOffset = 0xFFFFFFFF;
public class SectionBase : TreeNodeCustom
{
public long Position; //Offsets are relative to this
public string Signature;
public uint SectionSize;
public uint SubSectionSize;
public uint SubSectionOffset;
public uint NextSectionOffset;
public uint Unkown; //0xFFFFFFFF
public uint BinaryDataOffset; //32
public uint Unkown3; //0
public uint SubSectionCount;
public object BinaryData;
private byte[] binaryDataBytes;
public byte[] BinaryDataBytes
{
get
{
/* if (BinaryData == null)
return binaryDataBytes;
else if (BinaryData is BFRES)
return (((BFRES)BinaryData).Save());
else if (BinaryData is BNTX)
return (((BNTX)BinaryData).Save());
else*/
return binaryDataBytes;
}
set
{
binaryDataBytes = value;
}
}
public List<SectionBase> ChildSections = new List<SectionBase>();
public byte[] data;
public override void OnClick(TreeView treeview)
{
if (BinaryData is Emitter || Signature == "EMTR")
{
EmitterEditorNX editor = (EmitterEditorNX)LibraryGUI.GetActiveContent(typeof(EmitterEditorNX));
if (editor == null)
{
editor = new EmitterEditorNX();
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.Dock = DockStyle.Fill;
editor.LoadEmitter((Emitter)BinaryData);
}
}
public void Read(FileReader reader, Header ptclHeader, string MagicCheck = "")
{
Position = (uint)reader.Position;
if (MagicCheck != "")
Signature = reader.ReadSignature(4, MagicCheck);
else
Signature = reader.ReadString(4, Encoding.ASCII);
SectionSize = reader.ReadUInt32();
SubSectionOffset = reader.ReadUInt32();
NextSectionOffset = reader.ReadUInt32();
Unkown = reader.ReadUInt32();
BinaryDataOffset = reader.ReadUInt32();
Unkown3 = reader.ReadUInt32();
if (ptclHeader.Signature == "EFTB")
{
SubSectionCount = reader.ReadUInt16();
ushort unk = reader.ReadUInt16();
}
else
{
SubSectionCount = reader.ReadUInt32();
}
Text = Signature;
ReadSectionData(this, ptclHeader, reader);
if (SubSectionOffset != NullOffset)
{
uint tempCount = 0;
//Some sections will point to sub sections but have no count? (GRSN to GRSC)
//This will work decently for now
if (SubSectionCount == 0)
{
tempCount = 1;
}
reader.Seek(Position + SubSectionOffset, SeekOrigin.Begin);
for (int i = 0; i < SubSectionCount + tempCount; i++)
{
var ChildSection = new SectionBase();
Nodes.Add(ChildSection);
ChildSection.Read(reader, ptclHeader);
ChildSections.Add(ChildSection);
if (ChildSection.NextSectionOffset == NullOffset)
break;
}
}
reader.Seek(Position, SeekOrigin.Begin);
if (ChildSections.Count != 0)
data = reader.ReadBytes((int)SubSectionOffset);
else if (NextSectionOffset != NullOffset)
data = reader.ReadBytes((int)NextSectionOffset);
else
data = reader.ReadBytes((int)SectionSize);
if (NextSectionOffset != NullOffset)
reader.Seek(Position + NextSectionOffset, SeekOrigin.Begin);
}
private void ReadSectionData(SectionBase section, Header ptclHeader, FileReader reader)
{
if (section.BinaryDataOffset != NullOffset)
{
using (reader.TemporarySeek(section.BinaryDataOffset + section.Position, SeekOrigin.Begin))
{
BinaryDataBytes = reader.ReadBytes((int)section.SectionSize);
}
}
switch (section.Signature)
{
case "TEXR":
section.Text = "Texture Info";
BinaryData = new TEXR();
if (SubSectionCount > 0)
{
//Set the data block first!
reader.Seek(SubSectionOffset + section.Position, SeekOrigin.Begin);
var dataBlockSection = new SectionBase();
dataBlockSection.Read(reader, ptclHeader, "GX2B");
if (dataBlockSection.BinaryDataOffset != NullOffset)
{
reader.Seek(dataBlockSection.BinaryDataOffset + dataBlockSection.Position, SeekOrigin.Begin);
((TEXR)BinaryData).data = reader.ReadBytes((int)dataBlockSection.SectionSize);
}
}
reader.Seek(BinaryDataOffset + section.Position, SeekOrigin.Begin);
((TEXR)BinaryData).Read(reader, ptclHeader);
break;
case "SHDB":
reader.Seek(BinaryDataOffset + section.Position, SeekOrigin.Begin);
section.Text = "GTX Shader";
reader.ReadBytes((int)section.SectionSize);
break;
case "EMTR":
reader.Seek(BinaryDataOffset + 16 + section.Position, SeekOrigin.Begin);
Text = reader.ReadString(BinaryStringFormat.ZeroTerminated);
reader.Seek(BinaryDataOffset + 16 + 64 + section.Position, SeekOrigin.Begin);
BinaryData = new Emitter();
((Emitter)BinaryData).Read(reader, ptclHeader);
break;
case "ESTA":
section.Text = "Emitter Sets";
break;
case "ESET":
byte[] Padding = reader.ReadBytes(16);
section.Text = reader.ReadString(BinaryStringFormat.ZeroTerminated);
break;
case "GRTF":
if (section.BinaryDataOffset != NullOffset)
{
section.Text = "Textures";
reader.Seek(section.BinaryDataOffset + section.Position, SeekOrigin.Begin);
BinaryData = new BNTX();
((BNTX)BinaryData).LoadIcons = true;
((BNTX)BinaryData).FileName = "textures.bntx";
((BNTX)BinaryData).Load(new MemoryStream(reader.ReadBytes((int)section.SectionSize)));
((BNTX)BinaryData).IFileInfo.InArchive = true;
ptclHeader.BinaryTextureFile = ((BNTX)BinaryData);
Nodes.Add(((BNTX)BinaryData));
}
break;
case "PRMA":
break;
case "ESFT":
reader.Seek(28, SeekOrigin.Current);
int StringSize = reader.ReadInt32();
section.Text = reader.ReadString(StringSize, Encoding.ASCII);
break;
case "GRSN":
section.Text = "Shaders";
if (section.BinaryDataOffset != NullOffset)
{
reader.Seek(section.BinaryDataOffset + section.Position, SeekOrigin.Begin);
BinaryData = reader.ReadBytes((int)section.SectionSize);
}
break;
case "GRSC":
section.Text = "Shaders 2";
if (section.BinaryDataOffset != NullOffset)
{
reader.Seek(section.BinaryDataOffset + section.Position, SeekOrigin.Begin);
BinaryData = reader.ReadBytes((int)section.SectionSize);
}
break;
case "G3PR":
if (section.BinaryDataOffset != NullOffset)
{
section.Text = "Models";
reader.Seek(section.BinaryDataOffset + section.Position, SeekOrigin.Begin);
BinaryData = new BFRES();
((BFRES)BinaryData).FileName = "model.bfres";
((BFRES)BinaryData).Load(new MemoryStream(reader.ReadBytes((int)section.SectionSize)));
((BFRES)BinaryData).IFileInfo = new IFileInfo();
((BFRES)BinaryData).IFileInfo.InArchive = true;
Nodes.Add(((BFRES)BinaryData));
}
break;
case "GTNT":
if (section.BinaryDataOffset != NullOffset)
{
foreach (var node in Parent.Nodes)
{
if (node is BNTX)
{
BNTX bntx = (BNTX)node;
reader.Seek(section.BinaryDataOffset + section.Position, SeekOrigin.Begin);
for (int i = 0; i < bntx.Textures.Count; i++)
{
var texDescriptor = new TextureDescriptor();
Nodes.Add(texDescriptor);
texDescriptor.Read(reader, bntx);
}
}
}
}
break;
}
}
public void Write(FileWriter writer, PTCL.Header header)
{
switch (Signature)
{
case "GRSN":
SaveHeader(writer, header, BinaryDataBytes, 4096);
break;
case "GRSC":
SaveHeader(writer, header, BinaryDataBytes, 4096);
break;
case "G3PR":
// SaveHeader(writer, header, ((BFRES)BinaryData).Save(), 4096);
SaveHeader(writer, header, BinaryDataBytes, 4096);
break;
case "GRTF":
var mem = new System.IO.MemoryStream();
if (BinaryData != null)
{
((BNTX)BinaryData).Save(mem);
SaveHeader(writer, header, mem.ToArray(), 4096);
}
else
SaveHeader(writer, header, BinaryDataBytes, 4096);
break;
case "PRIM":
SaveHeader(writer, header, BinaryDataBytes);
break;
case "EMTR":
//Write all the data first
long _emitterPos = writer.Position;
writer.Write(data);
foreach (var child in ChildSections)
{
child.Write(writer, header);
}
using (writer.TemporarySeek(_emitterPos + BinaryDataOffset + 16 + 64, SeekOrigin.Begin))
{
((Emitter)BinaryData).Write(writer, header);
}
break;
default:
writer.Write(data);
foreach (var child in ChildSections)
{
child.Write(writer, header);
}
break;
}
/* writer.Write(Signature);
writer.Write(SectionSize);
writer.Write(SubSectionOffset);
writer.Write(NextSectionOffset);
writer.Write(Unkown);
writer.Write(Unkown3);
writer.Write(SubSectionCount);*/
}
public class BinarySavedEntry
{
public long Position;
public long _ofsData;
public byte[] Data;
}
public List<BinarySavedEntry> BinariesSaved = new List<BinarySavedEntry>();
private void SaveHeader(FileWriter writer, Header header, byte[] BinaryFile, int BinaryAlignment = 0)
{
if (Signature != "PRIM")
writer.Align(16);
if (BinaryFile != null && BinaryFile.Length > 0)
SectionSize = (uint)BinaryFile.Length;
long BasePosition = writer.Position;
writer.WriteSignature(Signature);
writer.Write(SectionSize);
long _ofsChildPos = writer.Position;
writer.Write(NullOffset); //Childern Offset for later
long _ofsNextPos = writer.Position;
writer.Write(NullOffset); //Next Offet for later
writer.Write(Unkown);
long _ofsBinaryPos = writer.Position;
writer.Write(NullOffset); //Binary Offset for later
writer.Write(Unkown3);
writer.Write(SubSectionCount);
if (ChildSections.Count > 0)
writer.WriteUint32Offset(_ofsChildPos, BasePosition);
foreach (var child in ChildSections)
{
if (child.BinaryData != null)
{
//Skip binaries for childern first
ChildHasBinary = true;
BinariesSaved.Add(new BinarySavedEntry()
{
Position = writer.Position,
_ofsData = writer.Position + 20,
Data = child.BinaryDataBytes,
});
child.Write(writer, header); //Save childern
ChildHasBinary = false; //Now all children headers have been written
}
else
child.Write(writer, header); //Save childern
}
if (!ChildHasBinary)
{
if (BinaryFile != null && BinaryFile.Length > 0)
{
if (BinaryAlignment != 0)
writer.Align(BinaryAlignment); //Align the file
Console.WriteLine($"{Signature} DATA BLOCK " + writer.Position + " " + BinaryFile.Length);
writer.WriteUint32Offset(_ofsBinaryPos, BasePosition); //Save binary offset
writer.Write(BinaryFile); //Save binary data
}
foreach (var binary in BinariesSaved)
{
writer.Align(4096); //Align the file
Console.WriteLine($"{Signature} DATA BLOCK " + writer.Position + " " + BinaryFile.Length);
writer.WriteUint32Offset(binary._ofsData, binary.Position); //Save binary offset
writer.Write(binary.Data); //Save binary data
}
BinariesSaved.Clear();
}
if (NextSectionOffset != NullOffset)
{
if (Signature != "PRIM")
writer.Align(16);
writer.WriteUint32Offset(_ofsNextPos, BasePosition);
}
}
}
public class TEXR : STGenericTexture
{
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.BC1_UNORM,
TEX_FORMAT.BC1_UNORM_SRGB,
TEX_FORMAT.BC2_UNORM,
TEX_FORMAT.BC2_UNORM_SRGB,
TEX_FORMAT.BC3_UNORM,
TEX_FORMAT.BC3_UNORM_SRGB,
TEX_FORMAT.BC4_UNORM,
TEX_FORMAT.BC4_SNORM,
TEX_FORMAT.BC5_UNORM,
TEX_FORMAT.BC5_SNORM,
TEX_FORMAT.B5G6R5_UNORM,
TEX_FORMAT.B8G8R8A8_UNORM_SRGB,
TEX_FORMAT.B8G8R8A8_UNORM,
TEX_FORMAT.B5G5R5A1_UNORM,
TEX_FORMAT.R8G8B8A8_UNORM_SRGB,
TEX_FORMAT.R8G8B8A8_UNORM,
TEX_FORMAT.R8_UNORM,
TEX_FORMAT.R8G8_UNORM,
};
}
}
public TEXR()
{
ImageKey = "Texture";
SelectedImageKey = "Texture";
}
public override void OnClick(TreeView treeView)
{
UpdateEditor();
}
public void UpdateEditor()
{
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.LoadProperties(GenericProperties);
editor.LoadImage(this);
}
public override bool CanEdit { get; set; } = false;
public enum SurfaceFormat : byte
{
INVALID = 0x0,
TCS_R8_G8_B8_A8 = 2,
T_BC1_UNORM = 3,
T_BC1_SRGB = 4,
T_BC2_UNORM = 5,
T_BC2_SRGB = 6,
T_BC3_UNORM = 7,
T_BC3_SRGB = 8,
T_BC4_UNORM = 9,
T_BC4_SNORM = 10,
T_BC5_UNORM = 11,
T_BC5_SNORM = 12,
TC_R8_UNORM = 13,
TC_R8_G8_UNORM = 14,
TCS_R8_G8_B8_A8_UNORM = 15,
TCS_R5_G6_B5_UNORM = 25,
};
public uint TileMode;
public uint Swizzle = 0;
public byte WrapMode = 11;
public byte Depth = 1;
public uint MipCount;
public uint CompSel;
public uint ImageSize;
public SurfaceFormat SurfFormat;
public byte[] data;
public uint TextureID;
public void Replace(string FileName)
{
}
public static GTXImporterSettings SetImporterSettings(string name)
{
var importer = new GTXImporterSettings();
string ext = System.IO.Path.GetExtension(name);
ext = ext.ToLower();
switch (ext)
{
case ".dds":
importer.LoadDDS(name);
break;
default:
importer.LoadBitMap(name);
break;
}
return importer;
}
public void Read(FileReader reader, Header header)
{
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
uint unk = reader.ReadUInt32();
CompSel = reader.ReadUInt32();
MipCount = reader.ReadUInt32();
uint unk2 = reader.ReadUInt32();
TileMode = reader.ReadUInt32();
uint unk3 = reader.ReadUInt32();
ImageSize = reader.ReadUInt32();
uint unk4 = reader.ReadUInt32();
TextureID = reader.ReadUInt32();
SurfFormat = reader.ReadEnum<SurfaceFormat>(false);
byte unk5 = reader.ReadByte();
short unk6 = reader.ReadInt16();
uint unk7 = reader.ReadUInt32();
}
public override void SetImageData(Bitmap bitmap, int ArrayLevel)
{
throw new NotImplementedException("Cannot set image data! Operation not implemented!");
}
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
uint GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC5_UNORM;
switch (SurfFormat)
{
case SurfaceFormat.T_BC1_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC1_UNORM;
Format = TEX_FORMAT.BC1_UNORM;
break;
case SurfaceFormat.T_BC1_SRGB:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC1_SRGB;
Format = TEX_FORMAT.BC1_UNORM_SRGB;
break;
case SurfaceFormat.T_BC2_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC2_UNORM;
Format = TEX_FORMAT.BC2_UNORM;
break;
case SurfaceFormat.T_BC2_SRGB:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC2_SRGB;
Format = TEX_FORMAT.BC2_UNORM_SRGB;
break;
case SurfaceFormat.T_BC3_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC3_UNORM;
Format = TEX_FORMAT.BC3_UNORM;
break;
case SurfaceFormat.T_BC3_SRGB:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC3_SRGB;
Format = TEX_FORMAT.BC3_UNORM_SRGB;
break;
case SurfaceFormat.T_BC4_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC4_UNORM;
Format = TEX_FORMAT.BC4_UNORM;
break;
case SurfaceFormat.T_BC4_SNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC4_SNORM;
Format = TEX_FORMAT.BC4_SNORM;
break;
case SurfaceFormat.T_BC5_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC5_UNORM;
Format = TEX_FORMAT.BC5_UNORM;
break;
case SurfaceFormat.T_BC5_SNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.T_BC5_SNORM;
Format = TEX_FORMAT.BC5_SNORM;
break;
case SurfaceFormat.TC_R8_G8_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.TC_R8_G8_UNORM;
Format = TEX_FORMAT.R8G8_UNORM;
break;
case SurfaceFormat.TCS_R8_G8_B8_A8_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.TCS_R8_G8_B8_A8_UNORM;
Format = TEX_FORMAT.R8G8B8A8_UNORM;
break;
case SurfaceFormat.TCS_R8_G8_B8_A8:
GX2Format = (uint)GX2.GX2SurfaceFormat.TCS_R8_G8_B8_A8_UNORM;
Format = TEX_FORMAT.R8G8B8A8_UNORM;
break;
case SurfaceFormat.TC_R8_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.TC_R8_UNORM;
Format = TEX_FORMAT.R8_UNORM;
break;
case SurfaceFormat.TCS_R5_G6_B5_UNORM:
GX2Format = (uint)GX2.GX2SurfaceFormat.TCS_R5_G6_B5_UNORM;
Format = TEX_FORMAT.B5G6R5_UNORM;
break;
default:
throw new Exception("Format unsupported! " + SurfFormat);
}
int swizzle = (int)Swizzle;
int pitch = (int)0;
uint bpp = GX2.surfaceGetBitsPerPixel(GX2Format) >> 3;
GX2.GX2Surface surf = new GX2.GX2Surface();
surf.bpp = bpp;
surf.height = Height;
surf.width = Width;
surf.aa = (uint)0;
surf.alignment = 0;
surf.depth = Depth;
surf.dim = 0x1;
surf.format = GX2Format;
surf.use = 0x1;
surf.pitch = 0;
surf.data = data;
surf.numMips = 1;
surf.mipOffset = new uint[0];
surf.mipData = null;
surf.tileMode = TileMode;
surf.swizzle = Swizzle;
surf.imageSize = ImageSize;
return GX2.Decode(surf, ArrayLevel, MipLevel);
}
public void Write(FileWriter writer)
{
}
}
public class Emitter : TreeNodeCustom
{
public List<STGenericTexture> DrawableTex = new List<STGenericTexture>();
public List<SamplerInfo> Samplers = new List<SamplerInfo>();
public STColor ConstantColor0;
public STColor ConstantColor1;
public STColor[] Color0Array = new STColor[8];
public STColor[] Color1Array = new STColor[8];
public STColor[] Color0AlphaArray = new STColor[8];
public STColor[] Color1AlphaArray = new STColor[8];
public STColor ConstantAlpha0
{
get
{
return new STColor()
{
R = ConstantColor0.A,
G = ConstantColor0.A,
B = ConstantColor0.A,
};
}
}
public STColor ConstantAlpha1
{
get
{
return new STColor()
{
R = ConstantColor1.A,
G = ConstantColor1.A,
B = ConstantColor1.A,
};
}
}
public enum ColorType
{
Constant,
Random,
Animated8Key,
}
public ColorType Color0Type;
public ColorType Alpha0Type;
public ColorType Color1Type;
public ColorType Alpha1Type;
private bool HasTime(STColor[] colors)
{
for (int i = 0; i < colors.Length; i++)
if (colors[i].Time != 0) return true;
return false;
}
private void SetType(bool HasKeys, STColor[] colors, int type, bool isAlpha)
{
if (HasKeys)
{
if (HasTime(colors))
SetType(type, isAlpha, ColorType.Animated8Key);
else
SetType(type, isAlpha, ColorType.Random);
}
else
SetType(type, isAlpha, ColorType.Constant);
}
private void SetType(int type, bool isAlpha, ColorType colorType)
{
if (type == 0)
{
if (!isAlpha)
Color0Type = colorType;
else
Alpha0Type = colorType;
}
if (type == 1)
{
if (!isAlpha)
Color1Type = colorType;
else
Alpha1Type = colorType;
}
}
public uint Color0KeyCount;
public uint Alpha0KeyCount;
public uint Color1KeyCount;
public uint Alpha1KeyCount;
public void Read(FileReader reader, Header ptclHeader)
{
uint Position = (uint)reader.Position;
Color0Array = new STColor[8];
Color1Array = new STColor[8];
Color0AlphaArray = new STColor[8];
Color1AlphaArray = new STColor[8];
ConstantColor0 = new STColor();
ConstantColor1 = new STColor();
reader.ReadBytes(16); //Unknown padding
Color0KeyCount = reader.ReadUInt32();
Alpha0KeyCount = reader.ReadUInt32();
Color1KeyCount = reader.ReadUInt32();
Alpha1KeyCount = reader.ReadUInt32();
uint scaleKeyCount = reader.ReadUInt32();
//Seek to the contant colors
if (ptclHeader.VFXVersion >= 37)
reader.Seek(Position + 2392, SeekOrigin.Begin);
else if (ptclHeader.VFXVersion > 21)
reader.Seek(Position + 2384, SeekOrigin.Begin);
else
reader.Seek(Position + 2392, SeekOrigin.Begin);
ConstantColor0 = new STColor();
ConstantColor0.R = reader.ReadSingle();
ConstantColor0.G = reader.ReadSingle();
ConstantColor0.B = reader.ReadSingle();
ConstantColor0.A = reader.ReadSingle();
ConstantColor1 = new STColor();
ConstantColor1.R = reader.ReadSingle();
ConstantColor1.G = reader.ReadSingle();
ConstantColor1.B = reader.ReadSingle();
ConstantColor1.A = reader.ReadSingle();
//Seek to the random and animated color table
reader.Seek(Position + 880, SeekOrigin.Begin);
for (int i = 0; i < 8; i++)
{
Color0Array[i] = new STColor();
Color0Array[i].R = reader.ReadSingle();
Color0Array[i].G = reader.ReadSingle();
Color0Array[i].B = reader.ReadSingle();
Color0Array[i].Time = reader.ReadSingle();
}
for (int i = 0; i < 8; i++)
{
Color0AlphaArray[i] = new STColor();
Color0AlphaArray[i].R = reader.ReadSingle();
Color0AlphaArray[i].G = reader.ReadSingle();
Color0AlphaArray[i].B = reader.ReadSingle();
Color0AlphaArray[i].Time = reader.ReadSingle();
}
for (int i = 0; i < 8; i++)
{
Color1Array[i] = new STColor();
Color1Array[i].R = reader.ReadSingle();
Color1Array[i].G = reader.ReadSingle();
Color1Array[i].B = reader.ReadSingle();
Color1Array[i].Time = reader.ReadSingle();
}
for (int i = 0; i < 8; i++)
{
Color1AlphaArray[i] = new STColor();
Color1AlphaArray[i].R = reader.ReadSingle();
Color1AlphaArray[i].G = reader.ReadSingle();
Color1AlphaArray[i].B = reader.ReadSingle();
Color1AlphaArray[i].Time = reader.ReadSingle();
int alpha = Utils.FloatToIntClamp(Color1Array[i].A);
}
SetType(Color0KeyCount != 0, Color0Array, 0, false);
SetType(Alpha0KeyCount != 0, Color0AlphaArray, 0, true);
SetType(Color1KeyCount != 0, Color1Array, 1, false);
SetType(Alpha1KeyCount != 0, Color1AlphaArray, 1, true);
if (ptclHeader.VFXVersion >= 37)
reader.Seek(Position + 2472, SeekOrigin.Begin);
else if (ptclHeader.VFXVersion > 21)
reader.Seek(Position + 2464, SeekOrigin.Begin);
else
reader.Seek(Position + 2472, SeekOrigin.Begin);
for (int i = 0; i < 3; i++)
{
SamplerInfo samplerInfo = new SamplerInfo();
samplerInfo.Read(reader);
Samplers.Add(samplerInfo);
}
}
public void Write(FileWriter writer, Header header)
{
uint Position = (uint)writer.Position;
//Seek to the contant colors
if (header.VFXVersion >= 37)
writer.Seek(Position + 2392, SeekOrigin.Begin);
else if (header.VFXVersion > 21)
writer.Seek(Position + 2384, SeekOrigin.Begin);
else
writer.Seek(Position + 2392, SeekOrigin.Begin);
writer.Write(ConstantColor0.R);
writer.Write(ConstantColor0.G);
writer.Write(ConstantColor0.B);
writer.Write(ConstantAlpha0.R);
writer.Write(ConstantColor1.R);
writer.Write(ConstantColor1.G);
writer.Write(ConstantColor1.B);
writer.Write(ConstantAlpha1.R);
writer.Seek(Position + 880, SeekOrigin.Begin);
for (int i = 0; i < 8; i++)
{
writer.Write(Color0Array[i].R);
writer.Write(Color0Array[i].G);
writer.Write(Color0Array[i].B);
writer.Write(Color0Array[i].Time);
}
for (int i = 0; i < 8; i++)
{
writer.Write(Color0AlphaArray[i].R);
writer.Write(Color0AlphaArray[i].G);
writer.Write(Color0AlphaArray[i].B);
writer.Write(Color0AlphaArray[i].Time);
}
for (int i = 0; i < 8; i++)
{
writer.Write(Color1Array[i].R);
writer.Write(Color1Array[i].G);
writer.Write(Color1Array[i].B);
writer.Write(Color1Array[i].Time);
}
for (int i = 0; i < 8; i++)
{
writer.Write(Color1AlphaArray[i].R);
writer.Write(Color1AlphaArray[i].G);
writer.Write(Color1AlphaArray[i].B);
writer.Write(Color1AlphaArray[i].Time);
}
}
public class SamplerInfo
{
public ulong TextureID;
public void Read(FileReader reader)
{
TextureID = reader.ReadUInt64();
byte wrapModeU = reader.ReadByte();
byte wrapMode = reader.ReadByte();
reader.Seek(22, SeekOrigin.Current);
}
}
private Color ReadColorRgba(FileReader reader, int amount = 1)
{
Color[] colors = new Color[amount];
for (int i = 0; i < 8; i++)
{
}
float R = reader.ReadSingle();
float G = reader.ReadSingle();
float B = reader.ReadSingle();
float A = reader.ReadSingle();
int red = Utils.FloatToIntClamp(R);
int green = Utils.FloatToIntClamp(G);
int blue = Utils.FloatToIntClamp(B);
int alpha = Utils.FloatToIntClamp(B);
return Color.FromArgb(255, red, green, blue);
}
private Color ReadColorAnim(FileReader reader, int amount = 1)
{
float R = reader.ReadSingle();
float G = reader.ReadSingle();
float B = reader.ReadSingle();
float unk = reader.ReadSingle();
int red = Utils.FloatToIntClamp(R);
int green = Utils.FloatToIntClamp(G);
int blue = Utils.FloatToIntClamp(B);
return Color.FromArgb(255, red, green, blue);
}
private Color ReadColorA(FileReader reader, int amount = 1)
{
float A = reader.ReadSingle();
float unk = reader.ReadSingle();
float unk2 = reader.ReadSingle();
float unk3 = reader.ReadSingle();
int alpha = Utils.FloatToIntClamp(A);
return Color.FromArgb(alpha, 0, 0, 0);
}
}
public class TextureDescriptor : TreeNodeCustom
{
public ulong TextureID;
public string TexName;
public void Read(FileReader reader, BNTX bntx)
{
uint Position = (uint)reader.Position; //Offsets are relative to this
TextureID = reader.ReadUInt64();
uint NextDesriptorOffset = reader.ReadUInt32();
uint StringLength = reader.ReadUInt32();
TexName = reader.ReadString(BinaryStringFormat.ZeroTerminated);
Text = TexName + " " + TextureID.ToString("x");
if (NextDesriptorOffset != 0)
reader.Seek(NextDesriptorOffset + Position, SeekOrigin.Begin);
}
}
}
}