mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-24 21:43:20 +00:00
Support latest BEA, multiple UVs for bfres, bounding box/shadow fixes, and more
This commit is contained in:
parent
44a88b4191
commit
bdec926c2d
16 changed files with 1634 additions and 65 deletions
|
@ -179,6 +179,12 @@ namespace FirstPlugin
|
|||
asset.FileName = node.FileName;
|
||||
asset.FileData = node.CompressedData;
|
||||
asset.UncompressedSize = node.FileData.Length;
|
||||
asset.FileID1 = node.FileID1;
|
||||
asset.FileID2 = node.FileID2;
|
||||
asset.FileHash = node.FileHash;
|
||||
asset.Unknown3 = node.Unknown3;
|
||||
asset.FileType = node.FileType;
|
||||
|
||||
beaFile.FileList.Add(asset.FileName, asset);
|
||||
beaFile.FileDictionary.Add(asset.FileName);
|
||||
}
|
||||
|
@ -204,6 +210,9 @@ namespace FirstPlugin
|
|||
public class FileEntry : ArchiveFileInfo
|
||||
{
|
||||
BEA ArchiveFile;
|
||||
|
||||
|
||||
|
||||
public FileEntry(BEA bea)
|
||||
{
|
||||
ArchiveFile = bea;
|
||||
|
@ -233,6 +242,11 @@ namespace FirstPlugin
|
|||
public ushort unk1;
|
||||
public ushort unk2;
|
||||
public bool IsCompressed;
|
||||
public ulong FileID1;
|
||||
public ulong FileID2;
|
||||
public uint FileHash;
|
||||
public string FileType = "";
|
||||
public uint Unknown3;
|
||||
|
||||
public override byte[] FileData
|
||||
{
|
||||
|
@ -248,6 +262,8 @@ namespace FirstPlugin
|
|||
unk1 = 2;
|
||||
unk2 = 12;
|
||||
FileData = data;
|
||||
FileID1 = (ulong)new Random().Next(0, int.MaxValue);
|
||||
FileID2 = (ulong)new Random().Next(0, int.MaxValue);
|
||||
}
|
||||
|
||||
public override Dictionary<string, string> ExtensionImageKeyLookup
|
||||
|
@ -309,6 +325,12 @@ namespace FirstPlugin
|
|||
fileEntry.unk2 = asset.unk2;
|
||||
fileEntry.IsCompressed = asset.IsCompressed;
|
||||
fileEntry.CompressedData = asset.FileData;
|
||||
fileEntry.Unknown3 = asset.Unknown3;
|
||||
fileEntry.FileID1 = asset.FileID1;
|
||||
fileEntry.FileID2 = asset.FileID2;
|
||||
fileEntry.FileHash = asset.FileHash;
|
||||
fileEntry.FileType = asset.FileType;
|
||||
|
||||
return fileEntry;
|
||||
}
|
||||
}
|
||||
|
|
96
File_Format_Library/FileFormats/Archives/BEA/ASST.cs
Normal file
96
File_Format_Library/FileFormats/Archives/BEA/ASST.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using Syroot.BinaryData;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace BezelEngineArchive_Lib
|
||||
{
|
||||
public class ASST : IFileData //File asset
|
||||
{
|
||||
private const string _signature = "ASST";
|
||||
|
||||
public ushort unk = 2;
|
||||
public ushort unk2 = 12;
|
||||
public string FileName;
|
||||
public long UncompressedSize;
|
||||
public bool IsCompressed = true;
|
||||
|
||||
public ulong FileID1;
|
||||
public ulong FileID2;
|
||||
|
||||
public uint FileHash;
|
||||
public uint Unknown3;
|
||||
|
||||
public byte[] FileData;
|
||||
|
||||
public uint FileSize;
|
||||
public long FileOffset;
|
||||
|
||||
public string FileType = "";
|
||||
|
||||
public BezelEngineArchive ParentArchive;
|
||||
|
||||
void IFileData.Load(FileLoader loader)
|
||||
{
|
||||
loader.CheckSignature(_signature);
|
||||
loader.LoadBlockHeader();
|
||||
unk = loader.ReadUInt16();
|
||||
unk2 = loader.ReadUInt16();
|
||||
FileSize = loader.ReadUInt32();
|
||||
UncompressedSize = loader.ReadUInt32();
|
||||
|
||||
if (loader.Archive.VersionMajor2 >= 5)
|
||||
{
|
||||
FileType = Encoding.ASCII.GetString(loader.ReadBytes(8));
|
||||
}
|
||||
|
||||
Unknown3 = loader.ReadUInt32();
|
||||
|
||||
if (loader.Archive.VersionMajor2 >= 6)
|
||||
{
|
||||
FileID1 = loader.ReadUInt64();
|
||||
FileID2 = loader.ReadUInt64();
|
||||
}
|
||||
|
||||
FileOffset = loader.ReadInt64();
|
||||
FileName = loader.LoadString();
|
||||
|
||||
using (loader.TemporarySeek(FileOffset, SeekOrigin.Begin)) {
|
||||
FileData = loader.ReadBytes((int)FileSize);
|
||||
}
|
||||
|
||||
if (UncompressedSize == FileSize)
|
||||
IsCompressed = false;
|
||||
}
|
||||
void IFileData.Save(FileSaver saver)
|
||||
{
|
||||
saver.WriteSignature(_signature);
|
||||
saver.SaveBlockHeader();
|
||||
saver.Write(unk);
|
||||
saver.Write(unk2);
|
||||
saver.Write((uint)FileData.Length);
|
||||
saver.Write((uint)UncompressedSize);
|
||||
|
||||
if (saver.Archive.VersionMajor2 >= 5)
|
||||
{
|
||||
if (FileType.Length > 8)
|
||||
throw new Exception($"Invalid file type length! Must be equal or less than 12 bytes! {FileType}!");
|
||||
|
||||
saver.Write(Encoding.ASCII.GetBytes(FileType));
|
||||
saver.Write(new byte[8 - FileType.Length]);
|
||||
}
|
||||
|
||||
saver.Write(Unknown3);
|
||||
|
||||
if (saver.Archive.VersionMajor2 >= 6)
|
||||
{
|
||||
saver.Write(FileID1);
|
||||
saver.Write(FileID2);
|
||||
}
|
||||
|
||||
saver.SaveBlock(FileData, (uint)saver.Archive.RawAlignment, () => saver.Write(FileData));
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "Asst File Name Offset");
|
||||
saver.SaveString(FileName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Syroot.BinaryData;
|
||||
using System.IO;
|
||||
|
||||
namespace BezelEngineArchive_Lib
|
||||
{
|
||||
public class BezelEngineArchive : IFileData
|
||||
{
|
||||
private const string _signature = "SCNE";
|
||||
|
||||
public BezelEngineArchive(Stream stream, bool leaveOpen = false)
|
||||
{
|
||||
using (FileLoader loader = new FileLoader(this, stream, leaveOpen))
|
||||
{
|
||||
loader.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
public BezelEngineArchive(string fileName)
|
||||
{
|
||||
using (FileLoader loader = new FileLoader(this, fileName))
|
||||
{
|
||||
loader.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
public ushort ByteOrder { get; private set; }
|
||||
public uint VersionMajor { get; set; }
|
||||
public uint VersionMajor2 { get; set; }
|
||||
public uint VersionMinor { get; set; }
|
||||
public uint VersionMinor2 { get; set; }
|
||||
public uint Alignment { get; set; }
|
||||
public uint TargetAddressSize { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string CompressionName { get; set; }
|
||||
|
||||
public ResDict FileDictionary { get; set; } //Todo, Need to setup ResDict to grab indexes quicker
|
||||
public Dictionary<string, ASST> FileList { get; set; } //Use a dictionary for now so i can look up files quickly
|
||||
|
||||
/// <summary>s
|
||||
/// Gets or sets the alignment to use for raw data blocks in the file.
|
||||
/// </summary>
|
||||
public int RawAlignment { get; set; }
|
||||
|
||||
public List<string> ReferenceList = new List<string>();
|
||||
|
||||
public void Save(Stream stream, bool leaveOpen = false)
|
||||
{
|
||||
using (FileSaver saver = new FileSaver(this, stream, leaveOpen))
|
||||
{
|
||||
saver.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(string FileName)
|
||||
{
|
||||
using (FileSaver saver = new FileSaver(this, FileName))
|
||||
{
|
||||
saver.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
internal uint SaveVersion()
|
||||
{
|
||||
return VersionMajor << 24 | VersionMajor2 << 16 | VersionMinor << 8 | VersionMinor2;
|
||||
}
|
||||
|
||||
private void SetVersionInfo(uint Version)
|
||||
{
|
||||
VersionMajor = Version >> 24;
|
||||
VersionMajor2 = Version >> 16 & 0xFF;
|
||||
VersionMinor = Version >> 8 & 0xFF;
|
||||
VersionMinor2 = Version & 0xFF;
|
||||
}
|
||||
|
||||
internal Stream _stream;
|
||||
|
||||
void IFileData.Load(FileLoader loader)
|
||||
{
|
||||
_stream = loader.BaseStream;
|
||||
|
||||
loader.CheckSignature(_signature);
|
||||
uint padding = loader.ReadUInt32();
|
||||
uint Version = loader.ReadUInt32();
|
||||
SetVersionInfo(Version);
|
||||
ByteOrder = loader.ReadUInt16();
|
||||
Alignment = (uint)loader.ReadByte();
|
||||
TargetAddressSize = (uint)loader.ReadByte();
|
||||
uint Padding = loader.ReadUInt32(); //Usually name offset for file with other switch formats
|
||||
ushort Padding2 = loader.ReadUInt16();
|
||||
ushort BlockOffset = loader.ReadUInt16(); //Goes to ASST section which seems to have block headers
|
||||
uint RelocationTableOffset = loader.ReadUInt32();
|
||||
uint DataOffset = loader.ReadUInt32(); //data or end of file offset
|
||||
var FileCount = loader.ReadUInt32();
|
||||
var RefCount = loader.ReadUInt32();
|
||||
|
||||
ulong FileInfoOffset = 0;
|
||||
|
||||
if (VersionMajor2 >= 5)
|
||||
{
|
||||
var AssetOffset = loader.ReadUInt64(); //asset offset
|
||||
FileInfoOffset = loader.ReadUInt64();
|
||||
FileDictionary = loader.LoadDict();
|
||||
Name = loader.LoadString();
|
||||
CompressionName = loader.LoadString();
|
||||
ulong RefOffset = loader.ReadUInt64();
|
||||
|
||||
ReferenceList = loader.LoadCustom(() =>
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
for (int i = 0; i < (int)RefCount; i++)
|
||||
list.Add(loader.LoadString());
|
||||
return list;
|
||||
|
||||
}, (long)RefOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileInfoOffset = loader.ReadUInt64();
|
||||
FileDictionary = loader.LoadDict();
|
||||
ulong unk = loader.ReadUInt64();
|
||||
Name = loader.LoadString();
|
||||
}
|
||||
|
||||
FileList = loader.LoadCustom(() =>
|
||||
{
|
||||
Dictionary<string, ASST> asstList = new Dictionary<string, ASST>();
|
||||
for (int i = 0; i < (int)FileCount; i++)
|
||||
{
|
||||
var asset = loader.Load<ASST>();
|
||||
asstList.Add(asset.FileName, asset);
|
||||
}
|
||||
return asstList;
|
||||
}, (long)FileInfoOffset);
|
||||
}
|
||||
void IFileData.Save(FileSaver saver)
|
||||
{
|
||||
RawAlignment = (1 << (int)Alignment);
|
||||
|
||||
saver.WriteSignature(_signature);
|
||||
saver.Write(0);
|
||||
saver.Write(SaveVersion());
|
||||
saver.Write(ByteOrder);
|
||||
saver.Write((byte)Alignment);
|
||||
saver.Write((byte)TargetAddressSize);
|
||||
saver.Write(0);
|
||||
saver.Write((ushort)0);
|
||||
saver.SaveFirstBlock();
|
||||
saver.SaveRelocationTablePointer();
|
||||
saver.SaveFileSize();
|
||||
saver.Write((uint)FileList.Count);
|
||||
saver.Write(ReferenceList == null ? 0u : (uint)ReferenceList.Count);
|
||||
|
||||
if (VersionMajor2 >= 5)
|
||||
{
|
||||
saver.SaveAssetBlock();
|
||||
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "Asst Offset Array");
|
||||
saver.SaveFileAsstPointer();
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "DIC");
|
||||
saver.SaveFileDictionaryPointer();
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "FileName");
|
||||
saver.SaveString(Name);
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "CompressionName");
|
||||
saver.SaveString(CompressionName);
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "Ref Offset");
|
||||
saver.SaveAssetRefPointer();
|
||||
}
|
||||
else
|
||||
{
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "Asst Offset Array");
|
||||
saver.SaveFileAsstPointer();
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "DIC");
|
||||
saver.SaveFileDictionaryPointer();
|
||||
saver.Write(0L);
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "FileName");
|
||||
saver.SaveString(Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
428
File_Format_Library/FileFormats/Archives/BEA/DIC/ResDict.cs
Normal file
428
File_Format_Library/FileFormats/Archives/BEA/DIC/ResDict.cs
Normal file
|
@ -0,0 +1,428 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BezelEngineArchive_Lib
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the non-generic base of a dictionary which can quickly look up <see cref="IResData"/> instances via
|
||||
/// key or index.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("Count = {Count}")]
|
||||
[DebuggerTypeProxy(typeof(TypeProxy))]
|
||||
public class ResDict : IEnumerable, IFileData
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private IList<Node> _nodes; // Includes root node.
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ResDict"/> class.
|
||||
/// </summary>
|
||||
public ResDict()
|
||||
{
|
||||
// Create root node.
|
||||
_nodes = new List<Node> { new Node() };
|
||||
}
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of instances stored.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return _nodes.Count - 1; }
|
||||
}
|
||||
|
||||
// ---- OPERATORS ----------------------------------------------------------------------------------------------
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given <paramref name="key"/> to insert in the dictionary.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Duplicated <paramref name="key"/> instances
|
||||
/// already exists.</exception>
|
||||
public void Add(string key)
|
||||
{
|
||||
if (!ContainsKey((key)))
|
||||
_nodes.Add(new Node(key));
|
||||
else
|
||||
throw new Exception($"key {key} already exists in the dictionary!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the given <paramref name="key"/> from the dictionary.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Duplicated <paramref name="key"/> instances
|
||||
/// already exists.</exception>
|
||||
public void Remove(string key)
|
||||
{
|
||||
_nodes.Remove(_nodes.Where(n => n.Key == key).FirstOrDefault());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the given <paramref name="key"/> is in the dictionary.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if <paramref name="key"/> was found in the dictionary; otherwise <c>false</c>.
|
||||
/// </returns>
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return _nodes.Any(p => p.Key == key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the key given <paramref name="index"/> is within range of the dictionary.
|
||||
/// </summary>
|
||||
public string GetKey(int index)
|
||||
{
|
||||
if (index < _nodes.Count || index > 0)
|
||||
return _nodes[index + 1].Key;
|
||||
else
|
||||
throw new Exception($"Index {index} is out of range!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all elements from the dictionary.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
// Create new collection with root node.
|
||||
_nodes.Clear();
|
||||
_nodes.Add(new Node());
|
||||
}
|
||||
|
||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||
|
||||
void IFileData.Load(FileLoader loader)
|
||||
{
|
||||
// Read the header.
|
||||
uint signature = loader.ReadUInt32(); //Always 0x00000000
|
||||
int numNodes = loader.ReadInt32(); // Excludes root node.
|
||||
|
||||
int i = 0;
|
||||
// Read the nodes including the root node.
|
||||
List<Node> nodes = new List<Node>();
|
||||
for (; numNodes >= 0; numNodes--)
|
||||
{
|
||||
nodes.Add(ReadNode(loader));
|
||||
i++;
|
||||
}
|
||||
_nodes = nodes;
|
||||
}
|
||||
|
||||
void IFileData.Save(FileSaver saver)
|
||||
{
|
||||
// Update the Patricia trie values in the nodes.
|
||||
UpdateNodes();
|
||||
|
||||
// Write header.
|
||||
saver.WriteSignature("_DIC");
|
||||
saver.Write(Count);
|
||||
|
||||
// Write nodes.
|
||||
int index = -1; // Start at -1 due to root node.
|
||||
int curNode = 0;
|
||||
foreach (Node node in _nodes)
|
||||
{
|
||||
saver.Write(node.Reference);
|
||||
saver.Write(node.IdxLeft);
|
||||
saver.Write(node.IdxRight);
|
||||
|
||||
if (curNode == 0)
|
||||
{
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "DIC " + node.Key); // <------------ Entry Set
|
||||
saver.SaveString("");
|
||||
}
|
||||
else
|
||||
{
|
||||
saver.SaveRelocateEntryToSection(saver.Position, 1, 1, 0, 1, "DIC " + node.Key); // <------------ Entry Set
|
||||
saver.SaveString(node.Key);
|
||||
}
|
||||
curNode++;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||
|
||||
IEnumerator<string> GetEnumerator()
|
||||
{
|
||||
foreach (Node node in Nodes)
|
||||
{
|
||||
yield return node.Key;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns only the publically visible nodes, excluding the root node.
|
||||
/// </summary>
|
||||
protected IEnumerable<Node> Nodes
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 1; i < _nodes.Count; i++)
|
||||
{
|
||||
yield return _nodes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
static string ToBinaryString(string text, Encoding encoding)
|
||||
{
|
||||
return string.Join("", encoding.GetBytes(text).Select(n => Convert.ToString(n, 2).PadLeft(8, '0')));
|
||||
}
|
||||
|
||||
static int _bit(BigInteger n, int b)
|
||||
{
|
||||
BigInteger test = (n >> (int)(b & 0xffffffff)) & 1;
|
||||
return (int)test;
|
||||
}
|
||||
|
||||
static int first_1bit(BigInteger n)
|
||||
{
|
||||
int bitlength1 = BitLength(n);
|
||||
for (int i = 0; i < bitlength1; i++)
|
||||
{
|
||||
if (((n >> i) & 1) == 1)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Operation Failed");
|
||||
}
|
||||
|
||||
static int bit_mismatch(BigInteger int1, BigInteger int2)
|
||||
{
|
||||
int bitlength1 = BitLength(int1);
|
||||
int bitlength2 = BitLength(int2);
|
||||
|
||||
for (int i = 0; i < Math.Max(bitlength1, bitlength2); i++)
|
||||
{
|
||||
if (((int1 >> i) & 1) != ((int2 >> i) & 1))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int BitLength(BigInteger bits)
|
||||
{
|
||||
int bitLength = 0;
|
||||
while (bits / 2 != 0)
|
||||
{
|
||||
bits /= 2;
|
||||
bitLength++;
|
||||
}
|
||||
bitLength += 1;
|
||||
return bitLength;
|
||||
}
|
||||
|
||||
class Tree
|
||||
{
|
||||
public Node root;
|
||||
|
||||
public Dictionary<BigInteger, Tuple<int, Node>> entries;
|
||||
|
||||
public Tree()
|
||||
{
|
||||
entries = new Dictionary<BigInteger, Tuple<int, Node>>();
|
||||
|
||||
root = new Node(0, -1, root);
|
||||
root.Parent = root;
|
||||
|
||||
insertEntry(0, root);
|
||||
}
|
||||
|
||||
int GetCompactBitIdx()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void insertEntry(BigInteger data, Node node)
|
||||
{
|
||||
entries[data] = (Tuple.Create(entries.Count, node));
|
||||
}
|
||||
|
||||
Node Search(BigInteger data, bool prev)
|
||||
{
|
||||
if (root.Child[0] == root)
|
||||
return root;
|
||||
|
||||
Node node = root.Child[0];
|
||||
Node prevNode = node;
|
||||
while (true)
|
||||
{
|
||||
prevNode = node;
|
||||
node = node.Child[_bit(data, node.bitInx)];
|
||||
if (node.bitInx <= prevNode.bitInx)
|
||||
break;
|
||||
}
|
||||
if (prev)
|
||||
return prevNode;
|
||||
else
|
||||
return node;
|
||||
}
|
||||
|
||||
public void Insert(string Name)
|
||||
{
|
||||
string bits = ToBinaryString(Name, Encoding.UTF8);
|
||||
BigInteger data = bits.Aggregate(new BigInteger(), (b, c) => b * 2 + c - '0');
|
||||
Node current = Search(data, true);
|
||||
int bitIdx = bit_mismatch(current.Data, data);
|
||||
|
||||
while (bitIdx < current.Parent.bitInx)
|
||||
current = current.Parent;
|
||||
|
||||
if (bitIdx < current.bitInx)
|
||||
{
|
||||
Node newNode = new Node(data, bitIdx, current.Parent);
|
||||
newNode.Child[_bit(data, bitIdx) ^ 1] = current;
|
||||
current.Parent.Child[_bit(data, current.Parent.bitInx)] = newNode;
|
||||
current.Parent = newNode;
|
||||
|
||||
insertEntry(data, newNode);
|
||||
}
|
||||
else if (bitIdx > current.bitInx)
|
||||
{
|
||||
Node newNode = new Node(data, bitIdx, current);
|
||||
if (_bit(current.Data, bitIdx) == (_bit(data, bitIdx) ^ 1))
|
||||
newNode.Child[_bit(data, bitIdx) ^ 1] = current;
|
||||
else
|
||||
newNode.Child[_bit(data, bitIdx) ^ 1] = root;
|
||||
|
||||
|
||||
current.Child[_bit(data, current.bitInx)] = newNode;
|
||||
insertEntry(data, newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
int NewBitIdx = first_1bit(data);
|
||||
|
||||
if (current.Child[_bit(data, bitIdx)] != root)
|
||||
NewBitIdx = bit_mismatch(current.Child[_bit(data, bitIdx)].Data, data);
|
||||
Node newNode = new Node(data, NewBitIdx, current);
|
||||
|
||||
newNode.Child[_bit(data, NewBitIdx) ^ 1] = current.Child[_bit(data, bitIdx)];
|
||||
current.Child[_bit(data, bitIdx)] = newNode;
|
||||
insertEntry(data, newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UpdateNodes()
|
||||
{
|
||||
Tree tree = new Tree();
|
||||
|
||||
// Create a new root node with empty key so the length can be retrieved throughout the process.
|
||||
_nodes[0] = new Node() { Key = String.Empty, bitInx = -1, Parent = _nodes[0] };
|
||||
|
||||
// Update the data-referencing nodes.
|
||||
for (ushort i = 1; i < _nodes.Count; i++)
|
||||
tree.Insert(_nodes[i].Key);
|
||||
|
||||
int CurEntry = 0;
|
||||
foreach (var entry in tree.entries.Values)
|
||||
{
|
||||
Node node = entry.Item2;
|
||||
|
||||
node.Reference = (uint)(node.GetCompactBitIdx() & 0xffffffff);
|
||||
node.IdxLeft = (ushort)tree.entries[node.Child[0].Data].Item1;
|
||||
node.IdxRight = (ushort)tree.entries[node.Child[1].Data].Item1;
|
||||
node.Key = node.GetName();
|
||||
_nodes[CurEntry] = node;
|
||||
|
||||
CurEntry++;
|
||||
}
|
||||
|
||||
// Remove the dummy empty key in the root again.
|
||||
_nodes[0].Key = null;
|
||||
}
|
||||
|
||||
private Node ReadNode(FileLoader loader)
|
||||
{
|
||||
return new Node()
|
||||
{
|
||||
Reference = loader.ReadUInt32(),
|
||||
IdxLeft = loader.ReadUInt16(),
|
||||
IdxRight = loader.ReadUInt16(),
|
||||
Key = loader.LoadString(),
|
||||
};
|
||||
}
|
||||
|
||||
// ---- CLASSES ------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Represents a node forming the Patricia trie of the dictionary.
|
||||
/// </summary>
|
||||
[DebuggerDisplay(nameof(Node) + " {" + nameof(Key) + "}")]
|
||||
protected class Node
|
||||
{
|
||||
internal const int SizeInBytes = 16;
|
||||
|
||||
internal List<Node> Child = new List<Node>();
|
||||
internal Node Parent;
|
||||
internal int bitInx;
|
||||
internal BigInteger Data;
|
||||
internal uint Reference;
|
||||
internal ushort IdxLeft;
|
||||
internal ushort IdxRight;
|
||||
internal string Key;
|
||||
|
||||
internal Node()
|
||||
{
|
||||
Child.Add(this);
|
||||
Child.Add(this);
|
||||
Reference = UInt32.MaxValue;
|
||||
}
|
||||
internal string GetName()
|
||||
{
|
||||
BigInteger data = BitLength(Data) + 7 / 8;
|
||||
byte[] stringBytes = Data.ToByteArray();
|
||||
Array.Reverse(stringBytes, 0, stringBytes.Length); //Convert to big endian
|
||||
return Encoding.UTF8.GetString(stringBytes); //Decode byte[] to string
|
||||
}
|
||||
internal int GetCompactBitIdx()
|
||||
{
|
||||
int byteIndx = bitInx / 8;
|
||||
return (byteIndx << 3) | bitInx - 8 * byteIndx;
|
||||
}
|
||||
internal Node(BigInteger data, int bitidx, Node parent) : this()
|
||||
{
|
||||
Data = data;
|
||||
bitInx = bitidx;
|
||||
Parent = parent;
|
||||
}
|
||||
internal Node(string key) : this()
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeProxy
|
||||
{
|
||||
private ResDict _dict;
|
||||
|
||||
internal TypeProxy(ResDict dict)
|
||||
{
|
||||
_dict = dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Syroot.BinaryData;
|
||||
|
||||
namespace BezelEngineArchive_Lib
|
||||
{
|
||||
//Thanks to Syroot for the IO and methods
|
||||
public class FileLoader : BinaryDataReader
|
||||
{
|
||||
private IDictionary<uint, IFileData> _dataMap;
|
||||
|
||||
public BezelEngineArchive Archive;
|
||||
|
||||
public FileLoader(BezelEngineArchive bea, Stream stream, bool leaveOpen = true)
|
||||
: base(stream, Encoding.ASCII, leaveOpen)
|
||||
{
|
||||
ByteOrder = ByteOrder.LittleEndian;
|
||||
Archive = bea;
|
||||
_dataMap = new Dictionary<uint, IFileData>();
|
||||
}
|
||||
|
||||
internal FileLoader(BezelEngineArchive bea, string fileName)
|
||||
: this(bea, new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
}
|
||||
|
||||
internal T LoadCustom<T>(Func<T> callback, long? offset = null)
|
||||
{
|
||||
offset = offset ?? ReadOffset();
|
||||
if (offset == 0) return default(T);
|
||||
|
||||
using (this.TemporarySeek(offset.Value, SeekOrigin.Begin))
|
||||
{
|
||||
return callback.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
internal string LoadString(Encoding encoding = null)
|
||||
{
|
||||
long offset = ReadInt64();
|
||||
if (offset == 0) return null;
|
||||
|
||||
encoding = encoding ?? Encoding;
|
||||
using (this.TemporarySeek(offset, SeekOrigin.Begin))
|
||||
{
|
||||
ushort count = ReadUInt16();
|
||||
return this.ReadString(count, encoding: encoding);
|
||||
}
|
||||
}
|
||||
internal void LoadBlockHeader()
|
||||
{
|
||||
uint offset = ReadUInt32();
|
||||
ulong size = ReadUInt64();
|
||||
}
|
||||
|
||||
internal void Execute()
|
||||
{
|
||||
Seek(0, SeekOrigin.Begin);
|
||||
((IFileData)Archive).Load(this);
|
||||
}
|
||||
|
||||
internal long ReadOffset()
|
||||
{
|
||||
long offset = ReadInt64();
|
||||
return offset == 0 ? 0 : offset;
|
||||
}
|
||||
|
||||
internal T Load<T>()
|
||||
where T : IFileData, new()
|
||||
{
|
||||
long offset = ReadOffset();
|
||||
if (offset == 0) return default(T);
|
||||
|
||||
// Seek to the instance data and load it.
|
||||
using (this.TemporarySeek(offset, SeekOrigin.Begin))
|
||||
{
|
||||
return ReadData<T>();
|
||||
}
|
||||
}
|
||||
|
||||
internal IList<T> LoadList<T>(int count, long? offset = null)
|
||||
where T : IFileData, new()
|
||||
{
|
||||
List<T> list = new List<T>(count);
|
||||
offset = offset ?? ReadOffset();
|
||||
if (offset == 0 || count == 0) return list;
|
||||
|
||||
// Seek to the list start and read it.
|
||||
using (this.TemporarySeek(offset.Value, SeekOrigin.Begin))
|
||||
{
|
||||
for (; count > 0; count--)
|
||||
{
|
||||
list.Add(ReadData<T>());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
internal ResDict LoadDict()
|
||||
{
|
||||
long offset = ReadInt64();
|
||||
if (offset == 0) return new ResDict();
|
||||
|
||||
using (this.TemporarySeek(offset, SeekOrigin.Begin))
|
||||
{
|
||||
ResDict dict = new ResDict();
|
||||
((IFileData)dict).Load(this);
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
||||
internal void CheckSignature(string validSignature)
|
||||
{
|
||||
// Read the actual signature and compare it.
|
||||
string signature = this.ReadString(sizeof(uint), Encoding.ASCII);
|
||||
if (signature != validSignature)
|
||||
{
|
||||
throw new Exception($"Invalid signature, expected '{validSignature}' but got '{signature}'.");
|
||||
}
|
||||
}
|
||||
|
||||
private T ReadData<T>()
|
||||
where T : IFileData, new()
|
||||
{
|
||||
uint offset = (uint)Position;
|
||||
|
||||
// Same data can be referenced multiple times. Load it in any case to move in the stream, needed for lists.
|
||||
T instance = new T();
|
||||
instance.Load(this);
|
||||
|
||||
// If possible, return an instance already representing the data.
|
||||
if (_dataMap.TryGetValue(offset, out IFileData existingInstance))
|
||||
{
|
||||
return (T)existingInstance;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataMap.Add(offset, instance);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,455 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Syroot.BinaryData;
|
||||
|
||||
namespace BezelEngineArchive_Lib
|
||||
{
|
||||
public class FileSaver : BinaryDataWriter
|
||||
{
|
||||
private IDictionary<string, StringEntry> _savedStrings;
|
||||
private List<long> _savedBlockPositions;
|
||||
private IDictionary<object, BlockEntry> _savedBlocks;
|
||||
private List<RelocationEntry> _savedSection1Entries;
|
||||
private List<RelocationSection> _savedRelocatedSections;
|
||||
private List<ItemEntry> _savedItems;
|
||||
|
||||
internal BezelEngineArchive Archive;
|
||||
private long _ofsFileSize;
|
||||
private long _ofsRelocationTable;
|
||||
private long _ofsFirstBlock;
|
||||
private long _ofsAsstArray;
|
||||
private long _ofsAsstRefArray;
|
||||
private long _ofsFileDictionary;
|
||||
private long _ofsEndOfBlock;
|
||||
private uint Section1Size;
|
||||
private uint beaSize; //Excludes data blocks
|
||||
private long _ofsAsstStart;
|
||||
|
||||
internal FileSaver(BezelEngineArchive bea, Stream stream, bool leaveOpen = true)
|
||||
: base(stream, Encoding.ASCII, leaveOpen)
|
||||
{
|
||||
ByteOrder = ByteOrder.LittleEndian;
|
||||
Archive = bea;
|
||||
}
|
||||
|
||||
internal FileSaver(BezelEngineArchive bea, string fileName)
|
||||
: this(bea, new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read), true)
|
||||
{
|
||||
}
|
||||
|
||||
internal void Execute()
|
||||
{
|
||||
_savedBlockPositions = new List<long>();
|
||||
_savedBlocks = new Dictionary<object, BlockEntry>();
|
||||
_savedSection1Entries = new List<RelocationEntry>();
|
||||
_savedStrings = new Dictionary<string, StringEntry>();
|
||||
_savedRelocatedSections = new List<RelocationSection>();
|
||||
|
||||
((IFileData)Archive).Save(this);
|
||||
|
||||
//Ref list for version 5 and up
|
||||
long RefOffset = Position; //Offset to blocks
|
||||
|
||||
if (Archive.ReferenceList != null)
|
||||
{
|
||||
SaveRelocateEntryToSection(Position, (uint)Archive.ReferenceList.Count, 1, 0, 1, "Ref String List ");
|
||||
foreach (var asstRef in Archive.ReferenceList)
|
||||
SaveString(asstRef);
|
||||
}
|
||||
|
||||
//Set enough space to add offsets later
|
||||
long OffsetArrayASST = Position; //Offset to blocks
|
||||
|
||||
List<long> _ofsAsstOffsets = new List<long>();
|
||||
foreach (ASST asst in Archive.FileList.Values)
|
||||
{
|
||||
SaveRelocateEntryToSection(Position, 1, 1, 0, 1, "Asst Offset ");
|
||||
_ofsAsstOffsets.Add(Position);
|
||||
Write(0L);
|
||||
}
|
||||
//Now padding. 40 per file
|
||||
Seek(40 * Archive.FileList.Count, SeekOrigin.Current);
|
||||
|
||||
//Now save dictionary.
|
||||
long DictionaryOffset = Position; //Offset to blocks
|
||||
((IFileData)Archive.FileDictionary).Save(this);
|
||||
|
||||
long BlockOffset = Position; //Offset to blocks
|
||||
for (int i = 0; i < Archive.FileList.Count; i++)
|
||||
{
|
||||
long AsstOffset = Position;
|
||||
using (this.TemporarySeek(_ofsAsstOffsets[i], SeekOrigin.Begin))
|
||||
{
|
||||
Write(AsstOffset);
|
||||
}
|
||||
string FileName = Archive.FileDictionary.GetKey(i);
|
||||
((IFileData)Archive.FileList[FileName]).Save(this);
|
||||
}
|
||||
|
||||
WriteStringPool();
|
||||
|
||||
|
||||
SetupRelocationTable();
|
||||
WriteRelocationTable();
|
||||
|
||||
WriteBlocks();
|
||||
|
||||
for (int i = 0; i < _savedBlockPositions.Count; i++)
|
||||
{
|
||||
Position = _savedBlockPositions[i];
|
||||
|
||||
if (i == _savedBlockPositions.Count - 1)
|
||||
{
|
||||
Write(0);
|
||||
Write(_ofsEndOfBlock - _savedBlockPositions[i]); //Size of string table to relocation table
|
||||
}
|
||||
else
|
||||
{
|
||||
uint blockSize = (uint)(_savedBlockPositions[i + 1] - _savedBlockPositions[i]);
|
||||
WriteHeaderBlock(blockSize, blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
Position = _ofsAsstArray;
|
||||
Write((ulong)OffsetArrayASST);
|
||||
|
||||
if (_ofsAsstStart != 0)
|
||||
{
|
||||
Position = _ofsAsstStart;
|
||||
Write((ulong)BlockOffset);
|
||||
}
|
||||
|
||||
Position = _ofsFirstBlock;
|
||||
Write((ushort)BlockOffset);
|
||||
|
||||
Position = _ofsFileDictionary;
|
||||
Write((ulong)DictionaryOffset);
|
||||
|
||||
if (_ofsAsstRefArray != 0)
|
||||
{
|
||||
Position = _ofsAsstRefArray;
|
||||
Write((ulong)RefOffset);
|
||||
}
|
||||
|
||||
Position = _ofsFileSize;
|
||||
Write(beaSize);
|
||||
Flush();
|
||||
}
|
||||
internal void SaveFirstBlock()
|
||||
{
|
||||
_ofsFirstBlock = Position;
|
||||
Write((ushort)0);
|
||||
}
|
||||
|
||||
internal void SaveAssetBlock()
|
||||
{
|
||||
_ofsAsstStart = Position;
|
||||
Write((ulong)0);
|
||||
}
|
||||
internal void SaveFileAsstPointer()
|
||||
{
|
||||
_ofsAsstArray = Position;
|
||||
Write(0L);
|
||||
}
|
||||
|
||||
|
||||
internal void SaveAssetRefPointer()
|
||||
{
|
||||
_ofsAsstRefArray = Position;
|
||||
Write(0L);
|
||||
}
|
||||
internal void SaveFileDictionaryPointer()
|
||||
{
|
||||
_ofsFileDictionary = Position;
|
||||
Write(0L);
|
||||
}
|
||||
internal void SaveRelocationTablePointer()
|
||||
{
|
||||
_ofsRelocationTable = Position;
|
||||
Write(0);
|
||||
}
|
||||
internal void SaveFileSize()
|
||||
{
|
||||
_ofsFileSize = Position;
|
||||
Write(0);
|
||||
}
|
||||
internal void WriteSize(uint Offset, uint value)
|
||||
{
|
||||
using (this.TemporarySeek(Offset, SeekOrigin.Begin))
|
||||
{
|
||||
Write(value);
|
||||
}
|
||||
}
|
||||
|
||||
internal uint SaveSizePtr()
|
||||
{
|
||||
Write(0);
|
||||
return (uint)Position;
|
||||
}
|
||||
internal void SaveBlockHeader()
|
||||
{
|
||||
_savedBlockPositions.Add(Position);
|
||||
Write(0);
|
||||
Write(0L);
|
||||
}
|
||||
internal void SaveBlock(object data, uint alignment, Action callback)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Write(0L);
|
||||
return;
|
||||
}
|
||||
if (_savedBlocks.TryGetValue(data, out BlockEntry entry))
|
||||
{
|
||||
entry.Offsets.Add((uint)Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
_savedBlocks.Add(data, new BlockEntry((uint)Position, alignment, callback));
|
||||
}
|
||||
Write(UInt64.MaxValue);
|
||||
}
|
||||
internal void SaveString(string str, Encoding encoding = null)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
Write(0L);
|
||||
return;
|
||||
}
|
||||
if (_savedStrings.TryGetValue(str, out StringEntry entry))
|
||||
{
|
||||
entry.Offsets.Add((uint)Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
_savedStrings.Add(str, new StringEntry((uint)Position, encoding));
|
||||
}
|
||||
Write(UInt64.MaxValue);
|
||||
}
|
||||
internal void WriteSignature(string value)
|
||||
{
|
||||
this.Write(Encoding.ASCII.GetBytes(value));
|
||||
}
|
||||
|
||||
//This only should use 1 section to relocate data
|
||||
internal void SaveRelocateEntryToSection(long pos, uint OffsetCount, uint StructCount, uint PaddingCount, int SectionNumber, string Hint)
|
||||
{
|
||||
if (SectionNumber == 1)
|
||||
_savedSection1Entries.Add(new RelocationEntry((uint)pos, OffsetCount, StructCount, PaddingCount, Hint));
|
||||
}
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
private void WriteHeaderBlock(uint Size, long Offset)
|
||||
{
|
||||
Write(Size);
|
||||
Write(Offset);
|
||||
}
|
||||
private void SetupRelocationTable()
|
||||
{
|
||||
this.Align(Archive.RawAlignment);
|
||||
RelocationSection FileMainSect;
|
||||
|
||||
long RelocationTableOffset = Position;
|
||||
|
||||
int EntryIndex = 0;
|
||||
uint EntryPos = 0;
|
||||
|
||||
foreach (RelocationEntry entry in _savedSection1Entries)
|
||||
{
|
||||
Console.WriteLine("Pos = " + entry.Position + " " + entry.StructCount + " " + entry.OffsetCount + " " + entry.PadingCount + " " + entry.Hint);
|
||||
}
|
||||
|
||||
_savedSection1Entries = _savedSection1Entries.OrderBy(o => o.Position).ToList();
|
||||
FileMainSect = new RelocationSection(EntryPos, EntryIndex, Section1Size, _savedSection1Entries);
|
||||
|
||||
_savedRelocatedSections.Add(FileMainSect);
|
||||
|
||||
}
|
||||
private void WriteRelocationTable()
|
||||
{
|
||||
uint relocationTableOffset = (uint)Position;
|
||||
WriteSignature("_RLT");
|
||||
_ofsEndOfBlock = (uint)Position;
|
||||
Write(relocationTableOffset);
|
||||
Write(_savedRelocatedSections.Count);
|
||||
Write(0); //padding
|
||||
|
||||
foreach (RelocationSection section in _savedRelocatedSections)
|
||||
{
|
||||
Write(0L); //padding
|
||||
Write(section.Position);
|
||||
Write(section.Size);
|
||||
Write(section.EntryIndex);
|
||||
Write(section.Entries.Count);
|
||||
}
|
||||
|
||||
foreach (RelocationSection section in _savedRelocatedSections)
|
||||
{
|
||||
foreach (RelocationEntry entry in section.Entries)
|
||||
{
|
||||
Write(entry.Position);
|
||||
Write((ushort)entry.StructCount);
|
||||
Write((byte)entry.OffsetCount);
|
||||
Write((byte)entry.PadingCount);
|
||||
}
|
||||
}
|
||||
|
||||
beaSize = (uint)Position;
|
||||
|
||||
using (this.TemporarySeek(_ofsRelocationTable, SeekOrigin.Begin))
|
||||
{
|
||||
Write(relocationTableOffset);
|
||||
}
|
||||
}
|
||||
private void WriteBlocks()
|
||||
{
|
||||
foreach (KeyValuePair<object, BlockEntry> entry in _savedBlocks)
|
||||
{
|
||||
// Align and satisfy offsets.
|
||||
Console.WriteLine(entry.Value.Alignment);
|
||||
Console.WriteLine(Position);
|
||||
if (entry.Value.Alignment != 0) this.Align((int)entry.Value.Alignment);
|
||||
Console.WriteLine(Position);
|
||||
|
||||
using (this.TemporarySeek())
|
||||
{
|
||||
SatisfyOffsets(entry.Value.Offsets, (uint)Position);
|
||||
}
|
||||
|
||||
// Write the data.
|
||||
entry.Value.Callback.Invoke();
|
||||
}
|
||||
}
|
||||
private void WriteStringPool()
|
||||
{
|
||||
WriteSignature("_STR");
|
||||
SaveBlockHeader();
|
||||
Write(_savedStrings.Count - 1);
|
||||
|
||||
foreach (KeyValuePair<string, StringEntry> entry in _savedStrings)
|
||||
{
|
||||
using (this.TemporarySeek())
|
||||
{
|
||||
SatisfyOffsets(entry.Value.Offsets, (uint)Position);
|
||||
}
|
||||
// Write the name.
|
||||
Write(entry.Key, BinaryStringFormat.WordLengthPrefix, entry.Value.Encoding ?? Encoding);
|
||||
Align(2);
|
||||
}
|
||||
Section1Size = (uint)Position;
|
||||
}
|
||||
|
||||
private void SatisfyOffsets(IEnumerable<uint> offsets, uint target)
|
||||
{
|
||||
foreach (uint offset in offsets)
|
||||
{
|
||||
Position = offset;
|
||||
Write((long)(target));
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetItemEntry(object data, ItemEntryType type, out ItemEntry entry)
|
||||
{
|
||||
foreach (ItemEntry savedItem in _savedItems)
|
||||
{
|
||||
if (savedItem.Data.Equals(data) && savedItem.Type == type)
|
||||
{
|
||||
entry = savedItem;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
entry = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private class StringEntry
|
||||
{
|
||||
internal List<uint> Offsets;
|
||||
internal Encoding Encoding;
|
||||
|
||||
internal StringEntry(uint offset, Encoding encoding = null)
|
||||
{
|
||||
Offsets = new List<uint>(new uint[] { offset });
|
||||
Encoding = encoding;
|
||||
}
|
||||
}
|
||||
private class BlockEntry
|
||||
{
|
||||
internal List<uint> Offsets;
|
||||
internal uint Alignment;
|
||||
internal Action Callback;
|
||||
|
||||
internal BlockEntry(uint offset, uint alignment, Action callback)
|
||||
{
|
||||
Offsets = new List<uint> { offset };
|
||||
Alignment = alignment;
|
||||
Callback = callback;
|
||||
}
|
||||
}
|
||||
private class RelocationSection
|
||||
{
|
||||
internal List<RelocationEntry> Entries;
|
||||
internal int EntryIndex;
|
||||
internal uint Size;
|
||||
internal uint Position;
|
||||
|
||||
internal RelocationSection(uint position, int entryIndex, uint size, List<RelocationEntry> entries)
|
||||
{
|
||||
Position = position;
|
||||
EntryIndex = entryIndex;
|
||||
Size = size;
|
||||
Entries = entries;
|
||||
}
|
||||
}
|
||||
private enum ItemEntryType
|
||||
{
|
||||
List, Dict, FileData, Custom
|
||||
}
|
||||
private class ItemEntry
|
||||
{
|
||||
internal object Data;
|
||||
internal ItemEntryType Type;
|
||||
internal List<uint> Offsets;
|
||||
internal uint? Target;
|
||||
internal Action Callback;
|
||||
internal int Index;
|
||||
|
||||
internal ItemEntry(object data, ItemEntryType type, uint? offset = null, uint? target = null,
|
||||
Action callback = null, int index = -1)
|
||||
{
|
||||
Data = data;
|
||||
Type = type;
|
||||
Offsets = new List<uint>();
|
||||
if (offset.HasValue) // Might be null for enumerable entries to resolve references to them later.
|
||||
{
|
||||
Offsets.Add(offset.Value);
|
||||
}
|
||||
Callback = callback;
|
||||
Target = target;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
private class RelocationEntry
|
||||
{
|
||||
internal uint Position;
|
||||
internal uint PadingCount;
|
||||
internal uint StructCount;
|
||||
internal uint OffsetCount;
|
||||
internal string Hint;
|
||||
|
||||
internal RelocationEntry(uint position, uint offsetCount, uint structCount, uint padingCount, string hint)
|
||||
{
|
||||
Position = position;
|
||||
StructCount = structCount;
|
||||
OffsetCount = offsetCount;
|
||||
PadingCount = padingCount;
|
||||
Hint = hint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
File_Format_Library/FileFormats/Archives/BEA/IO/IResData.cs
Normal file
22
File_Format_Library/FileFormats/Archives/BEA/IO/IResData.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
namespace BezelEngineArchive_Lib
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the common interface for <see cref="ResFile"/> data instances.
|
||||
/// </summary>
|
||||
public interface IFileData
|
||||
{
|
||||
// ---- METHODS ------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Loads raw data from the <paramref name="loader"/> data stream into instances.
|
||||
/// </summary>
|
||||
/// <param name="loader">The <see cref="ResFileLoader"/> to load data with.</param>
|
||||
void Load(FileLoader loader);
|
||||
|
||||
/// <summary>
|
||||
/// Saves header data of the instance and queues referenced data in the given <paramref name="saver"/>.
|
||||
/// </summary>
|
||||
/// <param name="saver">The <see cref="ResFileSaver"/> to save headers and queue data with.</param>
|
||||
void Save(FileSaver saver);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace BezelEngineArchive_Lib
|
||||
{
|
||||
public class SubStreamBea : Stream
|
||||
{
|
||||
Stream baseStream;
|
||||
readonly long length;
|
||||
readonly long baseOffset;
|
||||
public SubStreamBea(Stream baseStream, long offset, long length)
|
||||
{
|
||||
if (baseStream == null) throw new ArgumentNullException("baseStream");
|
||||
if (!baseStream.CanRead) throw new ArgumentException("baseStream.CanRead is false");
|
||||
if (!baseStream.CanSeek) throw new ArgumentException("baseStream.CanSeek is false");
|
||||
if (offset < 0) throw new ArgumentOutOfRangeException("offset");
|
||||
if (offset + length > baseStream.Length) throw new ArgumentOutOfRangeException("length");
|
||||
|
||||
this.baseStream = baseStream;
|
||||
this.length = length;
|
||||
baseOffset = offset;
|
||||
}
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
baseStream.Position = baseOffset + offset + Position;
|
||||
int read = baseStream.Read(buffer, offset, (int)Math.Min(count, length - Position));
|
||||
Position += read;
|
||||
return read;
|
||||
}
|
||||
public override long Length => length;
|
||||
public override bool CanRead => true;
|
||||
public override bool CanWrite => false;
|
||||
public override bool CanSeek => true;
|
||||
public override long Position { get; set; }
|
||||
public override void Flush() => baseStream.Flush();
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin: return Position = offset;
|
||||
case SeekOrigin.Current: return Position += offset;
|
||||
case SeekOrigin.End: return Position = length + offset;
|
||||
}
|
||||
throw new ArgumentException("origin is invalid");
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -773,7 +773,7 @@ namespace Bfres.Structs
|
|||
if (AttributeMatcher.ContainsKey(obj.ObjectName))
|
||||
shape.vertexAttributes = csvsettings.CreateNewAttributes(AttributeMatcher[obj.ObjectName]);
|
||||
else
|
||||
shape.vertexAttributes = csvsettings.CreateNewAttributes();
|
||||
shape.vertexAttributes = csvsettings.CreateNewAttributes(GetMaterial(shape.MaterialIndex));
|
||||
|
||||
shape.BoneIndex = 0;
|
||||
shape.Text = obj.ObjectName;
|
||||
|
@ -1304,12 +1304,6 @@ namespace Bfres.Structs
|
|||
|
||||
shape.VertexBufferIndex = shapes.Count;
|
||||
shape.vertices = obj.vertices;
|
||||
|
||||
if (AttributeMatcher.ContainsKey(obj.ObjectName))
|
||||
shape.vertexAttributes = settings.CreateNewAttributes(AttributeMatcher[obj.ObjectName]);
|
||||
else
|
||||
shape.vertexAttributes = settings.CreateNewAttributes();
|
||||
|
||||
shape.BoneIndex = obj.BoneIndex;
|
||||
|
||||
if (obj.MaterialIndex + MatStartIndex < materials.Count && obj.MaterialIndex > 0)
|
||||
|
@ -1317,6 +1311,11 @@ namespace Bfres.Structs
|
|||
else
|
||||
shape.MaterialIndex = 0;
|
||||
|
||||
if (AttributeMatcher.ContainsKey(obj.ObjectName))
|
||||
shape.vertexAttributes = settings.CreateNewAttributes(AttributeMatcher[obj.ObjectName]);
|
||||
else
|
||||
shape.vertexAttributes = settings.CreateNewAttributes(GetMaterial(shape.MaterialIndex));
|
||||
|
||||
shape.lodMeshes = obj.lodMeshes;
|
||||
shape.CreateBoneList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax);
|
||||
shape.CreateIndexList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax);
|
||||
|
|
|
@ -1400,16 +1400,17 @@ namespace Bfres.Structs
|
|||
max = CalculateBBMax(vertices);
|
||||
}
|
||||
|
||||
//Get the largest values in local space to create the largest bounding box
|
||||
foreach (var bounding in aabb)
|
||||
var c = (min + max) / 2.0f;
|
||||
var e = (max - min) / 2.0f;
|
||||
|
||||
float sphereRadius = (float)(c.Length + e.Length);
|
||||
|
||||
return new BoundingBox()
|
||||
{
|
||||
min.X = Math.Min(min.X, bounding.Min.X);
|
||||
min.Y = Math.Min(min.Y, bounding.Min.Y);
|
||||
min.Z = Math.Min(min.Z, bounding.Min.Z);
|
||||
max.X = Math.Max(max.X, bounding.Max.X);
|
||||
max.Y = Math.Max(max.Y, bounding.Max.Y);
|
||||
max.Z = Math.Max(max.Z, bounding.Max.Z);
|
||||
}
|
||||
Radius = sphereRadius,
|
||||
Center = new Vector3(c.X, c.Y, c.Z),
|
||||
Extend = new Vector3(e.X, e.Y, e.Z),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1756,6 +1757,22 @@ namespace Bfres.Structs
|
|||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
}
|
||||
if (att.Name == "_g3d_02_u0_u1")
|
||||
{
|
||||
VertexBufferHelperAttrib vert = new VertexBufferHelperAttrib();
|
||||
vert.Name = att.Name;
|
||||
vert.Data = uv0.ToArray();
|
||||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
}
|
||||
if (att.Name == "_g3d_02_u2_u3")
|
||||
{
|
||||
VertexBufferHelperAttrib vert = new VertexBufferHelperAttrib();
|
||||
vert.Name = att.Name;
|
||||
vert.Data = uv2.ToArray();
|
||||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
}
|
||||
if (att.Name == "_b0")
|
||||
{
|
||||
VertexBufferHelperAttrib vert = new VertexBufferHelperAttrib();
|
||||
|
@ -1780,6 +1797,31 @@ namespace Bfres.Structs
|
|||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
}
|
||||
if (att.Name == "_c1")
|
||||
{
|
||||
VertexBufferHelperAttrib vert = new VertexBufferHelperAttrib();
|
||||
vert.Name = att.Name;
|
||||
vert.Data = colors1.ToArray();
|
||||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
}
|
||||
if (att.Name == "_c2")
|
||||
{
|
||||
VertexBufferHelperAttrib vert = new VertexBufferHelperAttrib();
|
||||
vert.Name = att.Name;
|
||||
vert.Data = colors2.ToArray();
|
||||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
}
|
||||
|
||||
if (att.Name == "_c3")
|
||||
{
|
||||
VertexBufferHelperAttrib vert = new VertexBufferHelperAttrib();
|
||||
vert.Name = att.Name;
|
||||
vert.Data = colors3.ToArray();
|
||||
vert.Format = att.Format;
|
||||
atrib.Add(vert);
|
||||
}
|
||||
|
||||
// Set _w and _i
|
||||
for (int i = 0; i < weights.Count; i++)
|
||||
|
@ -1830,6 +1872,9 @@ namespace Bfres.Structs
|
|||
internal List<List<Syroot.Maths.Vector4F>> weights = new List<List<Syroot.Maths.Vector4F>>();
|
||||
internal List<List<Syroot.Maths.Vector4F>> boneInd = new List<List<Syroot.Maths.Vector4F>>();
|
||||
internal List<Syroot.Maths.Vector4F> colors = new List<Syroot.Maths.Vector4F>();
|
||||
internal List<Syroot.Maths.Vector4F> colors1 = new List<Syroot.Maths.Vector4F>();
|
||||
internal List<Syroot.Maths.Vector4F> colors2 = new List<Syroot.Maths.Vector4F>();
|
||||
internal List<Syroot.Maths.Vector4F> colors3 = new List<Syroot.Maths.Vector4F>();
|
||||
|
||||
public string GetBoneNameFromIndex(FMDL mdl, int index)
|
||||
{
|
||||
|
@ -2059,6 +2104,9 @@ namespace Bfres.Structs
|
|||
colors.Clear();
|
||||
weights.Clear();
|
||||
boneInd.Clear();
|
||||
colors1.Clear();
|
||||
colors2.Clear();
|
||||
colors3.Clear();
|
||||
|
||||
// Create arrays to be able to fit the needed skin count
|
||||
int listCount = (int)Math.Ceiling(VertexSkinCount / 4.0);
|
||||
|
@ -2086,12 +2134,15 @@ namespace Bfres.Structs
|
|||
|
||||
verts.Add(new Syroot.Maths.Vector4F(vtx.pos.X, vtx.pos.Y, vtx.pos.Z, 1.0f));
|
||||
norms.Add(new Syroot.Maths.Vector4F(vtx.nrm.X, vtx.nrm.Y, vtx.nrm.Z, 0));
|
||||
uv0.Add(new Syroot.Maths.Vector4F(vtx.uv0.X, vtx.uv0.Y, 0, 0));
|
||||
uv0.Add(new Syroot.Maths.Vector4F(vtx.uv0.X, vtx.uv0.Y, vtx.uv1.X, vtx.uv1.Y));
|
||||
uv1.Add(new Syroot.Maths.Vector4F(vtx.uv1.X, vtx.uv1.Y, 0, 0));
|
||||
uv2.Add(new Syroot.Maths.Vector4F(vtx.uv2.X, vtx.uv2.Y, 0, 0));
|
||||
uv2.Add(new Syroot.Maths.Vector4F(vtx.uv2.X, vtx.uv2.Y, vtx.uv3.X, vtx.uv3.Y));
|
||||
tans.Add(new Syroot.Maths.Vector4F(vtx.tan.X, vtx.tan.Y, vtx.tan.Z, vtx.tan.W));
|
||||
bitans.Add(new Syroot.Maths.Vector4F(vtx.bitan.X, vtx.bitan.Y, vtx.bitan.Z, vtx.bitan.W));
|
||||
colors.Add(new Syroot.Maths.Vector4F(vtx.col.X, vtx.col.Y, vtx.col.Z, vtx.col.W));
|
||||
colors1.Add(new Syroot.Maths.Vector4F(vtx.col2.X, vtx.col2.Y, vtx.col2.Z, vtx.col2.W));
|
||||
colors2.Add(new Syroot.Maths.Vector4F(vtx.col3.X, vtx.col3.Y, vtx.col3.Z, vtx.col3.W));
|
||||
colors3.Add(new Syroot.Maths.Vector4F(vtx.col4.X, vtx.col4.Y, vtx.col4.Z, vtx.col4.W));
|
||||
|
||||
// Init arrays based on skincount
|
||||
float[] weightsA = new float[TargetVertexSkinCount];
|
||||
|
|
|
@ -263,6 +263,9 @@ namespace FirstPlugin
|
|||
Syroot.Maths.Vector4F[] vec4uv1 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4uv2 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4c0 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4c1 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4c2 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4c3 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4t0 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4b0 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4w0 = new Syroot.Maths.Vector4F[0];
|
||||
|
@ -270,6 +273,9 @@ namespace FirstPlugin
|
|||
Syroot.Maths.Vector4F[] vec4i0 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4i1 = new Syroot.Maths.Vector4F[0];
|
||||
|
||||
Syroot.Maths.Vector4F[] vec4uv01 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4uv23 = new Syroot.Maths.Vector4F[0];
|
||||
|
||||
//For shape morphing
|
||||
Syroot.Maths.Vector4F[] vec4Positions1 = new Syroot.Maths.Vector4F[0];
|
||||
Syroot.Maths.Vector4F[] vec4Positions2 = new Syroot.Maths.Vector4F[0];
|
||||
|
@ -292,6 +298,12 @@ namespace FirstPlugin
|
|||
vec4uv2 = AttributeData(att, helper, "_u2");
|
||||
if (att.Name == "_c0")
|
||||
vec4c0 = AttributeData(att, helper, "_c0");
|
||||
if (att.Name == "_c1")
|
||||
vec4c1 = AttributeData(att, helper, "_c1");
|
||||
if (att.Name == "_c2")
|
||||
vec4c2 = AttributeData(att, helper, "_c2");
|
||||
if (att.Name == "_c3")
|
||||
vec4c3 = AttributeData(att, helper, "_c3");
|
||||
if (att.Name == "_t0")
|
||||
vec4t0 = AttributeData(att, helper, "_t0");
|
||||
if (att.Name == "_b0")
|
||||
|
@ -300,10 +312,10 @@ namespace FirstPlugin
|
|||
vec4w0 = AttributeData(att, helper, "_w0");
|
||||
if (att.Name == "_i0")
|
||||
vec4i0 = AttributeData(att, helper, "_i0");
|
||||
if (att.Name == "_w1")
|
||||
vec4w1 = AttributeData(att, helper, "_w1");
|
||||
if (att.Name == "_i1")
|
||||
vec4i1 = AttributeData(att, helper, "_i1");
|
||||
if (att.Name == "_g3d_02_u0_u1")
|
||||
vec4uv01 = AttributeData(att, helper, "_g3d_02_u0_u1");
|
||||
if (att.Name == "_g3d_02_u2_u3")
|
||||
vec4uv23 = AttributeData(att, helper, "_g3d_02_u2_u3");
|
||||
|
||||
if (att.Name == "_p1")
|
||||
vec4Positions1 = AttributeData(att, helper, "_p1");
|
||||
|
@ -330,6 +342,17 @@ namespace FirstPlugin
|
|||
if (vec4uv2.Length > 0)
|
||||
v.uv2 = new Vector2(vec4uv2[i].X, vec4uv2[i].Y);
|
||||
|
||||
if (vec4uv01.Length > 0)
|
||||
{
|
||||
v.uv0 = new Vector2(vec4uv01[i].X, vec4uv01[i].Y);
|
||||
v.uv1 = new Vector2(vec4uv01[i].Z, vec4uv01[i].W);
|
||||
}
|
||||
if (vec4uv23.Length > 0)
|
||||
{
|
||||
v.uv2 = new Vector2(vec4uv23[i].X, vec4uv23[i].Y);
|
||||
v.uv3 = new Vector2(vec4uv23[i].Z, vec4uv23[i].W);
|
||||
}
|
||||
|
||||
if (vec4w0.Length > 0)
|
||||
{
|
||||
if (fshp.VertexSkinCount > 0)
|
||||
|
@ -374,12 +397,19 @@ namespace FirstPlugin
|
|||
if (fshp.VertexSkinCount > 7)
|
||||
v.boneIds.Add((int)vec4i1[i].W);
|
||||
}
|
||||
|
||||
if (vec4t0.Length > 0)
|
||||
v.tan = new Vector4(vec4t0[i].X, vec4t0[i].Y, vec4t0[i].Z, vec4t0[i].W);
|
||||
if (vec4b0.Length > 0)
|
||||
v.bitan = new Vector4(vec4b0[i].X, vec4b0[i].Y, vec4b0[i].Z, vec4b0[i].W);
|
||||
if (vec4c0.Length > 0)
|
||||
v.col = new Vector4(vec4c0[i].X, vec4c0[i].Y, vec4c0[i].Z, vec4c0[i].W);
|
||||
if (vec4c1.Length > 0)
|
||||
v.col2 = new Vector4(vec4c1[i].X, vec4c1[i].Y, vec4c1[i].Z, vec4c1[i].W);
|
||||
if (vec4c2.Length > 0)
|
||||
v.col3 = new Vector4(vec4c2[i].X, vec4c2[i].Y, vec4c2[i].Z, vec4c2[i].W);
|
||||
if (vec4c3.Length > 0)
|
||||
v.col4 = new Vector4(vec4c3[i].X, vec4c3[i].Y, vec4c3[i].Z, vec4c3[i].W);
|
||||
|
||||
if (fshp.VertexSkinCount == 1)
|
||||
{
|
||||
|
@ -778,7 +808,6 @@ namespace FirstPlugin
|
|||
m.HasNormalMap = true;
|
||||
texture.Type = MatTexture.TextureType.Normal;
|
||||
}
|
||||
|
||||
else if (texture.SamplerName == "_e0")
|
||||
{
|
||||
m.HasEmissionMap = true;
|
||||
|
@ -796,7 +825,7 @@ namespace FirstPlugin
|
|||
}
|
||||
else if (texture.SamplerName == "_gn0") //Damage
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
// EOW Samplers
|
||||
else if (useSampler == "_albedo0")
|
||||
|
@ -1063,7 +1092,6 @@ namespace FirstPlugin
|
|||
m.HasEmissionMap = true;
|
||||
texture.Type = MatTexture.TextureType.Emission;
|
||||
}
|
||||
|
||||
else if (texture.SamplerName == "_s0" || useSampler == "_s0")
|
||||
{
|
||||
m.HasSpecularMap = true;
|
||||
|
@ -1084,14 +1112,11 @@ namespace FirstPlugin
|
|||
m.HasLightMap = true;
|
||||
texture.Type = MatTexture.TextureType.Light;
|
||||
}
|
||||
|
||||
else if (texture.SamplerName == "bake0")
|
||||
{
|
||||
m.HasShadowMap = true;
|
||||
texture.Type = MatTexture.TextureType.Shadow;
|
||||
}
|
||||
|
||||
// EOW Frag Samplers
|
||||
} // EOW Frag Samplers
|
||||
|
||||
else if (useSampler == "Albedo0")
|
||||
{
|
||||
|
|
|
@ -50,10 +50,6 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Toolbox\Lib\BcresLibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BezelEngineArchive_Lib">
|
||||
<HintPath>..\Toolbox\Lib\BezelEngineArchive_Lib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="BfshaLibrary, Version=1.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Toolbox\Lib\BfshaLibrary.dll</HintPath>
|
||||
|
@ -229,6 +225,13 @@
|
|||
<Compile Include="FileFormats\AAMP\AAMP.cs" />
|
||||
<Compile Include="FileFormats\Archives\APAK.cs" />
|
||||
<Compile Include="FileFormats\Archives\ARC.cs" />
|
||||
<Compile Include="FileFormats\Archives\BEA\ASST.cs" />
|
||||
<Compile Include="FileFormats\Archives\BEA\BevelEngineArchive.cs" />
|
||||
<Compile Include="FileFormats\Archives\BEA\DIC\ResDict.cs" />
|
||||
<Compile Include="FileFormats\Archives\BEA\IO\BinaryDataReader.cs" />
|
||||
<Compile Include="FileFormats\Archives\BEA\IO\BinaryDataWriter.cs" />
|
||||
<Compile Include="FileFormats\Archives\BEA\IO\IResData.cs" />
|
||||
<Compile Include="FileFormats\Archives\BEA\IO\SubStreamBea.cs" />
|
||||
<Compile Include="FileFormats\Archives\BNR.cs" />
|
||||
<Compile Include="FileFormats\Archives\DARC.cs" />
|
||||
<Compile Include="FileFormats\Archives\DAT_Bayonetta.cs" />
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
this.stCheckBox1 = new Toolbox.Library.Forms.STCheckBox();
|
||||
this.chkMapOriginalMaterials = new Toolbox.Library.Forms.STCheckBox();
|
||||
this.ogSkinCountChkBox = new Toolbox.Library.Forms.STCheckBox();
|
||||
this.combineUVs = new Toolbox.Library.Forms.STCheckBox();
|
||||
this.contentContainer.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.panel2.SuspendLayout();
|
||||
|
@ -460,6 +461,7 @@
|
|||
//
|
||||
// panel8
|
||||
//
|
||||
this.panel8.Controls.Add(this.combineUVs);
|
||||
this.panel8.Controls.Add(this.stLabel4);
|
||||
this.panel8.Controls.Add(this.lodCountUD);
|
||||
this.panel8.Controls.Add(this.chkCreateDummyLODs);
|
||||
|
@ -603,7 +605,6 @@
|
|||
this.chkBoxRotNegative90Y.Text = "Rotate -90 degrees";
|
||||
this.chkBoxRotNegative90Y.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.chkBoxRotNegative90Y.UseVisualStyleBackColor = true;
|
||||
this.chkBoxRotNegative90Y.CheckedChanged += new System.EventHandler(this.chkBoxSettings_CheckedChanged);
|
||||
//
|
||||
// textBoxMaterialPath
|
||||
//
|
||||
|
@ -836,7 +837,7 @@
|
|||
this.tabPageAdvanced.Location = new System.Drawing.Point(4, 25);
|
||||
this.tabPageAdvanced.Name = "tabPageAdvanced";
|
||||
this.tabPageAdvanced.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPageAdvanced.Size = new System.Drawing.Size(530, 347);
|
||||
this.tabPageAdvanced.Size = new System.Drawing.Size(192, 71);
|
||||
this.tabPageAdvanced.TabIndex = 0;
|
||||
this.tabPageAdvanced.Text = "Advanced Settings";
|
||||
//
|
||||
|
@ -853,7 +854,7 @@
|
|||
this.stPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.stPanel1.Location = new System.Drawing.Point(3, 3);
|
||||
this.stPanel1.Name = "stPanel1";
|
||||
this.stPanel1.Size = new System.Drawing.Size(524, 341);
|
||||
this.stPanel1.Size = new System.Drawing.Size(186, 65);
|
||||
this.stPanel1.TabIndex = 17;
|
||||
//
|
||||
// tabPage1
|
||||
|
@ -870,7 +871,7 @@
|
|||
this.tabPage1.Location = new System.Drawing.Point(4, 25);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(530, 347);
|
||||
this.tabPage1.Size = new System.Drawing.Size(192, 71);
|
||||
this.tabPage1.TabIndex = 2;
|
||||
this.tabPage1.Text = "Inject Mode";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
|
@ -981,6 +982,16 @@
|
|||
this.ogSkinCountChkBox.Text = "Keep Original Skin Count (can help crashes)";
|
||||
this.ogSkinCountChkBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// combineUVs
|
||||
//
|
||||
this.combineUVs.AutoSize = true;
|
||||
this.combineUVs.Location = new System.Drawing.Point(414, 88);
|
||||
this.combineUVs.Name = "combineUVs";
|
||||
this.combineUVs.Size = new System.Drawing.Size(90, 17);
|
||||
this.combineUVs.TabIndex = 40;
|
||||
this.combineUVs.Text = "Combine UVs";
|
||||
this.combineUVs.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// BfresModelImportSettings
|
||||
//
|
||||
this.ClientSize = new System.Drawing.Size(547, 412);
|
||||
|
@ -1097,5 +1108,6 @@
|
|||
private Toolbox.Library.Forms.STCheckBox chkCreateDummyLODs;
|
||||
private Toolbox.Library.Forms.STLabel stLabel4;
|
||||
private Toolbox.Library.Forms.NumericUpDownUint lodCountUD;
|
||||
private Toolbox.Library.Forms.STCheckBox combineUVs;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ using Toolbox.Library.Forms;
|
|||
using Toolbox.Library.Rendering;
|
||||
using Bfres.Structs;
|
||||
using System.Linq;
|
||||
using Syroot.NintenTools.NSW.Bfres;
|
||||
using static OpenTK.Graphics.OpenGL.GL;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
|
@ -65,6 +67,8 @@ namespace FirstPlugin
|
|||
public bool ResetUVParams;
|
||||
public bool ResetColorParams;
|
||||
|
||||
public bool CombineUVs => combineUVs.Checked;
|
||||
|
||||
public bool LimitSkinCount => ogSkinCountChkBox.Checked;
|
||||
public bool MapOriginalMaterials
|
||||
{
|
||||
|
@ -181,13 +185,18 @@ namespace FirstPlugin
|
|||
Attributes[i].Format = (AttribFormat)comboBoxFormatWeights.SelectedItem;
|
||||
if (Attributes[i].Name == "_i0")
|
||||
Attributes[i].Format = (AttribFormat)comboBoxFormatIndices.SelectedItem;
|
||||
|
||||
if (CombineUVs && Attributes[i].Name == "_u0")
|
||||
Attributes[i].Format = AttribFormat.Format_16_16_16_16_Single;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return Attributes;
|
||||
}
|
||||
|
||||
public List<FSHP.VertexAttribute> CreateNewAttributes()
|
||||
public List<FSHP.VertexAttribute> CreateNewAttributes(FMAT material = null)
|
||||
{
|
||||
Dictionary<string, FSHP.VertexAttribute> attribute = new Dictionary<string, FSHP.VertexAttribute>();
|
||||
|
||||
|
@ -230,20 +239,35 @@ namespace FirstPlugin
|
|||
FSHP.VertexAttribute att = new FSHP.VertexAttribute();
|
||||
att.Name = "_u0";
|
||||
att.Format = (AttribFormat)comboBoxFormatUvs.SelectedItem;
|
||||
|
||||
if (material.shaderassign.attributes.ContainsValue("_g3d_02_u0_u1"))
|
||||
{
|
||||
att.Format = AttribFormat.Format_16_16_16_16_Single;
|
||||
att.Name = "_g3d_02_u0_u1";
|
||||
}
|
||||
|
||||
attribute.Add(att.Name, att);
|
||||
}
|
||||
if (EnableUV1 && EnableUV0)
|
||||
if (EnableUV1 && EnableUV0 && !attribute.ContainsKey("_g3d_02_u0_u1"))
|
||||
{
|
||||
FSHP.VertexAttribute att = new FSHP.VertexAttribute();
|
||||
att.Name = "_u1";
|
||||
att.Format = (AttribFormat)comboBoxFormatUvs.SelectedItem;
|
||||
attribute.Add(att.Name, att);
|
||||
}
|
||||
|
||||
if (EnableUV2 && EnableUV0)
|
||||
{
|
||||
FSHP.VertexAttribute att = new FSHP.VertexAttribute();
|
||||
att.Name = "_u2";
|
||||
att.Format = (AttribFormat)comboBoxFormatUvs.SelectedItem;
|
||||
|
||||
if (material.shaderassign.attributes.ContainsValue("_g3d_02_u2_u3"))
|
||||
{
|
||||
att.Format = AttribFormat.Format_16_16_16_16_Single;
|
||||
att.Name = "_g3d_02_u2_u3";
|
||||
}
|
||||
|
||||
attribute.Add(att.Name, att);
|
||||
}
|
||||
if (EnableTangents)
|
||||
|
@ -275,6 +299,25 @@ namespace FirstPlugin
|
|||
attribute.Add(att.Name, att);
|
||||
}
|
||||
|
||||
if (material.shaderassign.attributes.ContainsValue("_c0") && !EnableVertexColors)
|
||||
{
|
||||
FSHP.VertexAttribute att = new FSHP.VertexAttribute();
|
||||
att.Name = "_c0";
|
||||
att.Format = (AttribFormat)comboBoxFormatVertexColors.SelectedItem;
|
||||
attribute.Add(att.Name, att);
|
||||
}
|
||||
|
||||
for (int i = 1; i < 6; i++)
|
||||
{
|
||||
if (material.shaderassign.attributes.ContainsValue($"_c{i}"))
|
||||
{
|
||||
FSHP.VertexAttribute att = new FSHP.VertexAttribute();
|
||||
att.Name = $"_c{i}";
|
||||
att.Format = (AttribFormat)comboBoxFormatVertexColors.SelectedItem;
|
||||
attribute.Add(att.Name, att);
|
||||
}
|
||||
}
|
||||
|
||||
switch ((GamePreset)gamePresetCB.SelectedItem)
|
||||
{
|
||||
//Use single buffer
|
||||
|
@ -492,12 +535,10 @@ namespace FirstPlugin
|
|||
|
||||
int assimpIndex = assimpMeshListView.SelectedIndices[0];
|
||||
|
||||
objectNameTB.BackColor = System.Drawing.Color.DarkRed;
|
||||
foreach (ListViewItem item in originalMeshListView.Items)
|
||||
{
|
||||
if (objectNameTB.Text == item.Text)
|
||||
objectNameTB.BackColor = System.Drawing.Color.Green;
|
||||
}
|
||||
if (objectNameTB.Text == originalMeshListView.Items[assimpIndex].Text)
|
||||
objectNameTB.BackColor = System.Drawing.Color.Green;
|
||||
else
|
||||
objectNameTB.BackColor = System.Drawing.Color.DarkRed;
|
||||
|
||||
NewMeshlist[assimpIndex].ObjectName = objectNameTB.Text;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ using Toolbox.Library.IO;
|
|||
|
||||
namespace Toolbox.Library
|
||||
{
|
||||
public class DAE
|
||||
public class DAE
|
||||
{
|
||||
public class ExportSettings
|
||||
{
|
||||
|
@ -55,11 +55,12 @@ namespace Toolbox.Library
|
|||
new List<STGenericMaterial>(), new List<STGenericTexture>());
|
||||
}
|
||||
|
||||
public static void Export(string FileName, ExportSettings settings, STGenericModel model, List<STGenericTexture> Textures, STSkeleton skeleton = null, List<int> NodeArray = null) {
|
||||
Export(FileName, settings, model.Objects.ToList(), model.Materials.ToList(), Textures, skeleton, NodeArray);
|
||||
public static void Export(string FileName, ExportSettings settings, STGenericModel model, List<STGenericTexture> Textures, STSkeleton skeleton = null, List<int> NodeArray = null)
|
||||
{
|
||||
Export(FileName, settings, model.Objects.ToList(), model.Materials.ToList(), Textures, skeleton, NodeArray);
|
||||
}
|
||||
|
||||
public static void Export(string FileName, ExportSettings settings,
|
||||
public static void Export(string FileName, ExportSettings settings,
|
||||
List<STGenericObject> Meshes, List<STGenericMaterial> Materials,
|
||||
List<STGenericTexture> Textures, STSkeleton skeleton = null, List<int> NodeArray = null)
|
||||
{
|
||||
|
@ -102,7 +103,8 @@ namespace Toolbox.Library
|
|||
if (!textureNames.Contains(Textures[i].Text))
|
||||
textureNames.Add(Textures[i].Text);
|
||||
|
||||
if (settings.ExportTextures) {
|
||||
if (settings.ExportTextures)
|
||||
{
|
||||
|
||||
progressBar.Task = $"Exporting Texture {Textures[i].Text}";
|
||||
progressBar.Value = ((i * 100) / Textures.Count);
|
||||
|
@ -137,7 +139,8 @@ namespace Toolbox.Library
|
|||
GC.Collect();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Exception ex)
|
||||
{
|
||||
failedTextureExport.Add(Textures[i].Text);
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +192,7 @@ namespace Toolbox.Library
|
|||
texMap.WrapModeT = SamplerWrapMode.WRAP;
|
||||
else if (tex.WrapModeT == STTextureWrapMode.Mirror)
|
||||
texMap.WrapModeT = SamplerWrapMode.MIRROR;
|
||||
else if(tex.WrapModeT == STTextureWrapMode.Clamp)
|
||||
else if (tex.WrapModeT == STTextureWrapMode.Clamp)
|
||||
texMap.WrapModeT = SamplerWrapMode.CLAMP;
|
||||
|
||||
|
||||
|
@ -210,7 +213,8 @@ namespace Toolbox.Library
|
|||
else
|
||||
writer.WriteLibraryImages();
|
||||
|
||||
if (skeleton != null) {
|
||||
if (skeleton != null)
|
||||
{
|
||||
//Search for bones with rigging first
|
||||
List<string> riggedBones = new List<string>();
|
||||
if (settings.OnlyExportRiggedBones)
|
||||
|
@ -223,7 +227,8 @@ namespace Toolbox.Library
|
|||
for (int j = 0; j < vertex.boneIds.Count; j++)
|
||||
{
|
||||
int id = -1;
|
||||
if (NodeArray != null && NodeArray.Count > vertex.boneIds[j]) {
|
||||
if (NodeArray != null && NodeArray.Count > vertex.boneIds[j])
|
||||
{
|
||||
id = NodeArray[vertex.boneIds[j]];
|
||||
}
|
||||
else
|
||||
|
@ -288,7 +293,7 @@ namespace Toolbox.Library
|
|||
if (mesh.MaterialIndex != -1 && Materials.Count > mesh.MaterialIndex)
|
||||
{
|
||||
writer.CurrentMaterial = Materials[mesh.MaterialIndex].Text;
|
||||
Console.WriteLine($"MaterialIndex {mesh.MaterialIndex } {Materials[mesh.MaterialIndex].Text}");
|
||||
Console.WriteLine($"MaterialIndex {mesh.MaterialIndex} {Materials[mesh.MaterialIndex].Text}");
|
||||
}
|
||||
|
||||
|
||||
|
@ -312,18 +317,21 @@ namespace Toolbox.Library
|
|||
transform = diffuse.Transform;
|
||||
|
||||
var vertexA = mesh.vertices[faces[v]];
|
||||
var vertexB = mesh.vertices[faces[v+1]];
|
||||
var vertexC = mesh.vertices[faces[v+2]];
|
||||
var vertexB = mesh.vertices[faces[v + 1]];
|
||||
var vertexC = mesh.vertices[faces[v + 2]];
|
||||
|
||||
if (!transformedVertices.Contains(vertexA)) {
|
||||
if (!transformedVertices.Contains(vertexA))
|
||||
{
|
||||
vertexA.uv0 = (vertexA.uv0 * transform.Scale) + transform.Translate;
|
||||
transformedVertices.Add(vertexA);
|
||||
}
|
||||
if (!transformedVertices.Contains(vertexB)) {
|
||||
if (!transformedVertices.Contains(vertexB))
|
||||
{
|
||||
vertexB.uv0 = (vertexB.uv0 * transform.Scale) + transform.Translate;
|
||||
transformedVertices.Add(vertexB);
|
||||
}
|
||||
if (!transformedVertices.Contains(vertexC)) {
|
||||
if (!transformedVertices.Contains(vertexC))
|
||||
{
|
||||
vertexC.uv0 = (vertexC.uv0 * transform.Scale) + transform.Translate;
|
||||
transformedVertices.Add(vertexC);
|
||||
}
|
||||
|
@ -340,15 +348,20 @@ namespace Toolbox.Library
|
|||
List<float> UV3 = new List<float>();
|
||||
List<float> Color = new List<float>();
|
||||
List<float> Color2 = new List<float>();
|
||||
List<float> Color3 = new List<float>();
|
||||
List<float> Color4 = new List<float>();
|
||||
List<int[]> BoneIndices = new List<int[]>();
|
||||
List<float[]> BoneWeights = new List<float[]>();
|
||||
|
||||
bool HasNormals = false;
|
||||
bool HasColors = false;
|
||||
bool HasColors2 = false;
|
||||
bool HasColors3 = false;
|
||||
bool HasColors4 = false;
|
||||
bool HasUV0 = false;
|
||||
bool HasUV1 = false;
|
||||
bool HasUV2 = false;
|
||||
bool HasUV3 = false;
|
||||
bool HasBoneIds = false;
|
||||
|
||||
foreach (var vertex in mesh.vertices)
|
||||
|
@ -356,9 +369,13 @@ namespace Toolbox.Library
|
|||
if (vertex.nrm != Vector3.Zero) HasNormals = true;
|
||||
if (vertex.col != Vector4.One && settings.UseVertexColors) HasColors = true;
|
||||
if (vertex.col2 != Vector4.One && settings.UseVertexColors) HasColors2 = true;
|
||||
if (vertex.col3 != Vector4.One && settings.UseVertexColors) HasColors3 = true;
|
||||
if (vertex.col4 != Vector4.One && settings.UseVertexColors) HasColors4 = true;
|
||||
|
||||
if (vertex.uv0 != Vector2.Zero) HasUV0 = true;
|
||||
if (vertex.uv1 != Vector2.Zero) HasUV1 = true;
|
||||
if (vertex.uv2 != Vector2.Zero) HasUV2 = true;
|
||||
if (vertex.uv3 != Vector2.Zero) HasUV3 = true;
|
||||
if (vertex.boneIds.Count > 0) HasBoneIds = true;
|
||||
|
||||
Position.Add(vertex.pos.X); Position.Add(vertex.pos.Y); Position.Add(vertex.pos.Z);
|
||||
|
@ -369,16 +386,20 @@ namespace Toolbox.Library
|
|||
UV0.Add(vertex.uv0.X); UV0.Add(1 - vertex.uv0.Y);
|
||||
UV1.Add(vertex.uv1.X); UV1.Add(1 - vertex.uv1.Y);
|
||||
UV2.Add(vertex.uv2.X); UV2.Add(1 - vertex.uv2.Y);
|
||||
UV3.Add(vertex.uv3.X); UV3.Add(1 - vertex.uv3.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
UV0.Add(vertex.uv0.X); UV0.Add(vertex.uv0.Y);
|
||||
UV1.Add(vertex.uv1.X); UV1.Add(vertex.uv1.Y);
|
||||
UV2.Add(vertex.uv2.X); UV2.Add(vertex.uv2.Y);
|
||||
UV3.Add(vertex.uv3.X); UV3.Add(vertex.uv3.Y);
|
||||
}
|
||||
|
||||
Color.AddRange(new float[] { vertex.col.X, vertex.col.Y, vertex.col.Z, vertex.col.W });
|
||||
Color2.AddRange(new float[] { vertex.col2.X, vertex.col2.Y, vertex.col2.Z, vertex.col2.W });
|
||||
Color3.AddRange(new float[] { vertex.col3.X, vertex.col3.Y, vertex.col3.Z, vertex.col3.W });
|
||||
Color4.AddRange(new float[] { vertex.col4.X, vertex.col4.Y, vertex.col4.Z, vertex.col4.W });
|
||||
|
||||
List<int> bIndices = new List<int>();
|
||||
List<float> bWeights = new List<float>();
|
||||
|
@ -446,7 +467,7 @@ namespace Toolbox.Library
|
|||
foreach (var group in mesh.PolygonGroups)
|
||||
{
|
||||
TriangleList triangleList = new TriangleList();
|
||||
|
||||
|
||||
triangleLists.Add(triangleList);
|
||||
|
||||
STGenericMaterial material = new STGenericMaterial();
|
||||
|
@ -484,9 +505,12 @@ namespace Toolbox.Library
|
|||
|
||||
if (HasColors)
|
||||
writer.WriteGeometrySource(mesh.Text, SemanticType.COLOR, Color.ToArray(), triangleLists.ToArray(), 0);
|
||||
|
||||
if (HasColors2)
|
||||
writer.WriteGeometrySource(mesh.Text, SemanticType.COLOR, Color2.ToArray(), triangleLists.ToArray(), 1);
|
||||
if (HasColors3)
|
||||
writer.WriteGeometrySource(mesh.Text, SemanticType.COLOR, Color3.ToArray(), triangleLists.ToArray(), 2);
|
||||
if (HasColors4)
|
||||
writer.WriteGeometrySource(mesh.Text, SemanticType.COLOR, Color4.ToArray(), triangleLists.ToArray(), 3);
|
||||
|
||||
if (HasUV0)
|
||||
writer.WriteGeometrySource(mesh.Text, SemanticType.TEXCOORD, UV0.ToArray(), triangleLists.ToArray(), 0);
|
||||
|
@ -497,6 +521,9 @@ namespace Toolbox.Library
|
|||
if (HasUV2)
|
||||
writer.WriteGeometrySource(mesh.Text, SemanticType.TEXCOORD, UV2.ToArray(), triangleLists.ToArray(), 2);
|
||||
|
||||
if (HasUV3)
|
||||
writer.WriteGeometrySource(mesh.Text, SemanticType.TEXCOORD, UV3.ToArray(), triangleLists.ToArray(), 3);
|
||||
|
||||
if (HasBoneIds)
|
||||
writer.AttachGeometryController(BoneIndices, BoneWeights);
|
||||
|
||||
|
@ -508,7 +535,7 @@ namespace Toolbox.Library
|
|||
progressBar?.Close();
|
||||
|
||||
if (!settings.SuppressConfirmDialog)
|
||||
System.Windows.Forms.MessageBox.Show($"Exported {FileName} successfully!");
|
||||
System.Windows.Forms.MessageBox.Show($"Exported {FileName} Successfully!");
|
||||
}
|
||||
|
||||
|
||||
|
@ -530,7 +557,7 @@ namespace Toolbox.Library
|
|||
|
||||
COLLADA collada = COLLADA.Load(FileName);
|
||||
|
||||
|
||||
|
||||
//Check axis up
|
||||
if (collada.asset != null)
|
||||
{
|
||||
|
@ -593,7 +620,7 @@ namespace Toolbox.Library
|
|||
|
||||
private void LoadNodes(library_nodes nodes)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void LoadMaterials(library_materials materials)
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace Toolbox.Library.Rendering
|
|||
public Vector3 nrm = new Vector3(0);
|
||||
public Vector4 col = new Vector4(1);
|
||||
public Vector4 col2 = new Vector4(1);
|
||||
public Vector4 col3 = new Vector4(1);
|
||||
public Vector4 col4 = new Vector4(1);
|
||||
|
||||
public Vector2 uv0 = new Vector2(0);
|
||||
public Vector2 uv1 = new Vector2(0);
|
||||
|
|
Loading…
Reference in a new issue