2019-06-02 20:08:10 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2019-06-13 23:31:35 +02:00
|
|
|
|
using System.IO;
|
2019-06-22 00:18:22 +02:00
|
|
|
|
using System.Linq;
|
2019-06-02 20:08:10 +02:00
|
|
|
|
using System.Threading.Tasks;
|
2019-07-16 23:35:21 +02:00
|
|
|
|
using Toolbox;
|
2019-06-02 20:08:10 +02:00
|
|
|
|
using System.Windows.Forms;
|
2019-07-16 23:35:21 +02:00
|
|
|
|
using Toolbox.Library;
|
|
|
|
|
using Toolbox.Library.IO;
|
|
|
|
|
using Toolbox.Library.Forms;
|
|
|
|
|
using Toolbox.Library.Rendering;
|
2019-06-22 00:18:22 +02:00
|
|
|
|
using OpenTK;
|
2019-06-02 20:08:10 +02:00
|
|
|
|
|
|
|
|
|
namespace FirstPlugin
|
|
|
|
|
{
|
|
|
|
|
public class GFBMDL : TreeNodeFile, IFileFormat
|
|
|
|
|
{
|
|
|
|
|
public FileType FileType { get; set; } = FileType.Model;
|
|
|
|
|
|
|
|
|
|
public bool CanSave { get; set; }
|
|
|
|
|
public string[] Description { get; set; } = new string[] { "Graphic Model" };
|
|
|
|
|
public string[] Extension { get; set; } = new string[] { "*.gfbmdl" };
|
|
|
|
|
public string FileName { get; set; }
|
|
|
|
|
public string FilePath { get; set; }
|
|
|
|
|
public IFileInfo IFileInfo { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool Identify(System.IO.Stream stream)
|
|
|
|
|
{
|
2019-07-16 23:35:21 +02:00
|
|
|
|
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
|
2019-06-02 20:08:10 +02:00
|
|
|
|
{
|
|
|
|
|
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
|
|
|
|
|
|
|
|
|
|
bool IsMatch = reader.ReadUInt32() == 0x20000000;
|
|
|
|
|
reader.Position = 0;
|
|
|
|
|
|
|
|
|
|
return IsMatch;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Type[] Types
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
List<Type> types = new List<Type>();
|
|
|
|
|
return types.ToArray();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-20 23:20:06 +02:00
|
|
|
|
Viewport viewport
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2019-07-11 23:22:59 +02:00
|
|
|
|
var editor = LibraryGUI.GetObjectEditor();
|
2019-06-20 23:20:06 +02:00
|
|
|
|
return editor.GetViewport();
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
2019-07-11 23:22:59 +02:00
|
|
|
|
var editor = LibraryGUI.GetObjectEditor();
|
2019-06-20 23:20:06 +02:00
|
|
|
|
editor.LoadViewport(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DrawablesLoaded = false;
|
|
|
|
|
public override void OnClick(TreeView treeView)
|
|
|
|
|
{
|
|
|
|
|
if (Runtime.UseOpenGL)
|
|
|
|
|
{
|
|
|
|
|
if (viewport == null)
|
|
|
|
|
{
|
|
|
|
|
viewport = new Viewport(ObjectEditor.GetDrawableContainers());
|
|
|
|
|
viewport.Dock = DockStyle.Fill;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DrawablesLoaded)
|
|
|
|
|
{
|
|
|
|
|
ObjectEditor.AddContainer(DrawableContainer);
|
|
|
|
|
DrawablesLoaded = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewport.ReloadDrawables(DrawableContainer);
|
2019-07-11 23:22:59 +02:00
|
|
|
|
LibraryGUI.LoadEditor(viewport);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
|
|
|
|
|
viewport.Text = Text;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 23:31:35 +02:00
|
|
|
|
public Header header;
|
2019-06-22 00:18:22 +02:00
|
|
|
|
public GFBMDL_Render Renderer;
|
|
|
|
|
|
2019-06-20 23:20:06 +02:00
|
|
|
|
public DrawableContainer DrawableContainer = new DrawableContainer();
|
2019-06-13 23:31:35 +02:00
|
|
|
|
|
2019-06-02 20:08:10 +02:00
|
|
|
|
public void Load(System.IO.Stream stream)
|
|
|
|
|
{
|
2019-06-21 00:01:06 +02:00
|
|
|
|
Text = FileName;
|
2019-06-20 23:20:06 +02:00
|
|
|
|
DrawableContainer.Name = FileName;
|
2019-06-22 00:18:22 +02:00
|
|
|
|
Renderer = new GFBMDL_Render();
|
2019-06-20 23:20:06 +02:00
|
|
|
|
|
2019-06-13 23:31:35 +02:00
|
|
|
|
header = new Header();
|
2019-06-21 00:01:06 +02:00
|
|
|
|
header.Read(new FileReader(stream), this);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
|
2019-06-22 04:24:33 +02:00
|
|
|
|
ContextMenuStrip = new STContextMenuStrip();
|
|
|
|
|
ContextMenuStrip.Items.Add(new ToolStripMenuItem("Export Model", null, ExportModelAction, Keys.Control | Keys.E));
|
2019-06-02 20:08:10 +02:00
|
|
|
|
}
|
2019-06-22 04:24:33 +02:00
|
|
|
|
|
|
|
|
|
private void ExportModelAction(object sender, EventArgs args) {
|
|
|
|
|
ExportModel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ExportModel()
|
|
|
|
|
{
|
|
|
|
|
SaveFileDialog sfd = new SaveFileDialog();
|
|
|
|
|
sfd.Filter = "Supported Formats|*.dae;";
|
|
|
|
|
if (sfd.ShowDialog() == DialogResult.OK)
|
|
|
|
|
{
|
|
|
|
|
ExportModel(sfd.FileName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ExportModel(string FileName)
|
|
|
|
|
{
|
|
|
|
|
AssimpSaver assimp = new AssimpSaver();
|
|
|
|
|
ExportModelSettings settings = new ExportModelSettings();
|
|
|
|
|
|
|
|
|
|
var model = new STGenericModel();
|
|
|
|
|
model.Materials = header.GenericMaterials;
|
|
|
|
|
model.Objects = Renderer.Meshes;
|
|
|
|
|
|
|
|
|
|
assimp.SaveFromModel(model, FileName, new List<STGenericTexture>(), ((STSkeleton)DrawableContainer.Drawables[0]));
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-02 20:08:10 +02:00
|
|
|
|
public void Unload()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
2019-06-22 04:24:33 +02:00
|
|
|
|
|
2019-06-02 20:08:10 +02:00
|
|
|
|
public byte[] Save()
|
|
|
|
|
{
|
2019-06-13 23:31:35 +02:00
|
|
|
|
var mem = new System.IO.MemoryStream();
|
|
|
|
|
header.Write(new FileWriter(mem));
|
|
|
|
|
return mem.ToArray();
|
2019-06-02 20:08:10 +02:00
|
|
|
|
}
|
2019-06-02 22:15:33 +02:00
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
//Todo replace tedius offset handling with a class to store necessary data and methods to execute
|
2019-06-13 23:31:35 +02:00
|
|
|
|
public class Header
|
|
|
|
|
{
|
2019-06-20 23:20:06 +02:00
|
|
|
|
public STSkeleton Skeleton { get; set; }
|
|
|
|
|
|
2019-06-13 23:31:35 +02:00
|
|
|
|
public uint Version { get; set; }
|
|
|
|
|
public float[] Boundings { get; set; }
|
2019-06-22 17:11:00 +02:00
|
|
|
|
public List<string> ShaderNames = new List<string>();
|
2019-06-13 23:31:35 +02:00
|
|
|
|
public List<string> TextureMaps = new List<string>();
|
2019-06-22 00:18:22 +02:00
|
|
|
|
public List<string> MaterialNames = new List<string>();
|
|
|
|
|
public List<VertexBuffer> VertexBuffers = new List<VertexBuffer>();
|
|
|
|
|
public List<VisGroup> VisualGroups = new List<VisGroup>();
|
|
|
|
|
public List<MaterialShaderData> Materials = new List<MaterialShaderData>();
|
|
|
|
|
|
|
|
|
|
public List<GFBMaterial> GenericMaterials = new List<GFBMaterial>();
|
2019-06-13 23:31:35 +02:00
|
|
|
|
|
2019-06-21 00:01:06 +02:00
|
|
|
|
public void Read(FileReader reader, GFBMDL Root)
|
2019-06-13 23:31:35 +02:00
|
|
|
|
{
|
2019-06-20 23:20:06 +02:00
|
|
|
|
Skeleton = new STSkeleton();
|
2019-06-21 00:01:06 +02:00
|
|
|
|
Root.DrawableContainer.Drawables.Add(Skeleton);
|
2019-06-22 00:18:22 +02:00
|
|
|
|
Root.DrawableContainer.Drawables.Add(Root.Renderer);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
|
2019-06-13 23:31:35 +02:00
|
|
|
|
reader.SetByteOrder(false);
|
|
|
|
|
|
|
|
|
|
Version = reader.ReadUInt32();
|
|
|
|
|
Boundings = reader.ReadSingles(9);
|
|
|
|
|
long TextureOffset = reader.ReadOffset(true, typeof(uint));
|
2019-06-22 17:11:00 +02:00
|
|
|
|
long ShaderNameOffset = reader.ReadOffset(true, typeof(uint));
|
2019-06-22 00:18:22 +02:00
|
|
|
|
long Unknown1ffset = reader.ReadOffset(true, typeof(uint));
|
2019-06-22 17:11:00 +02:00
|
|
|
|
long MaterialNameOffset = reader.ReadOffset(true, typeof(uint));
|
2019-06-13 23:31:35 +02:00
|
|
|
|
long ShaderOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
long VisGroupOffset = reader.ReadOffset(true, typeof(uint));
|
2019-06-22 00:18:22 +02:00
|
|
|
|
long VerteBufferOffset = reader.ReadOffset(true, typeof(uint));
|
2019-06-13 23:31:35 +02:00
|
|
|
|
long BoneDataOffset = reader.ReadOffset(true, typeof(uint));
|
2019-06-02 22:15:33 +02:00
|
|
|
|
|
2019-06-13 23:31:35 +02:00
|
|
|
|
if (TextureOffset != 0)
|
|
|
|
|
{
|
2019-06-22 00:18:22 +02:00
|
|
|
|
reader.SeekBegin(TextureOffset);
|
2019-06-13 23:31:35 +02:00
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
TextureMaps = reader.ReadNameOffsets(Count, true, typeof(uint), true);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 17:11:00 +02:00
|
|
|
|
if (ShaderNameOffset != 0)
|
2019-06-13 23:31:35 +02:00
|
|
|
|
{
|
2019-06-22 17:11:00 +02:00
|
|
|
|
reader.SeekBegin(ShaderNameOffset);
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
ShaderNames = reader.ReadNameOffsets(Count, true, typeof(uint));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MaterialNameOffset != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(MaterialNameOffset);
|
2019-06-13 23:31:35 +02:00
|
|
|
|
uint Count = reader.ReadUInt32();
|
2019-06-22 00:18:22 +02:00
|
|
|
|
MaterialNames = reader.ReadNameOffsets(Count, true, typeof(uint));
|
2019-06-13 23:31:35 +02:00
|
|
|
|
}
|
2019-06-20 23:20:06 +02:00
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
|
|
|
|
|
if (ShaderOffset != 0)
|
2019-06-20 23:20:06 +02:00
|
|
|
|
{
|
2019-06-22 00:18:22 +02:00
|
|
|
|
reader.SeekBegin(ShaderOffset);
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
MaterialShaderData shaderData = new MaterialShaderData();
|
|
|
|
|
shaderData.Read(reader);
|
|
|
|
|
Materials.Add(shaderData);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-21 00:01:06 +02:00
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
if (VisGroupOffset != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(VisGroupOffset);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
uint Count = reader.ReadUInt32();
|
2019-06-22 00:18:22 +02:00
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
VisGroup visualGroup = new VisGroup();
|
|
|
|
|
visualGroup.Read(reader);
|
|
|
|
|
VisualGroups.Add(visualGroup);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-20 23:20:06 +02:00
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
if (VerteBufferOffset != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(VerteBufferOffset);
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
VertexBuffer vertexBuffer = new VertexBuffer();
|
|
|
|
|
vertexBuffer.Read(reader);
|
|
|
|
|
VertexBuffers.Add(vertexBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BoneDataOffset != 0)
|
|
|
|
|
{
|
|
|
|
|
TreeNode SkeletonWrapper = new TreeNode("Skeleton");
|
|
|
|
|
Root.Nodes.Add(SkeletonWrapper);
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(BoneDataOffset);
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
2019-06-20 23:20:06 +02:00
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var bone = new Bone(Skeleton);
|
|
|
|
|
bone.Read(reader);
|
|
|
|
|
Skeleton.bones.Add(bone);
|
|
|
|
|
}
|
2019-06-21 00:01:06 +02:00
|
|
|
|
|
|
|
|
|
foreach (var bone in Skeleton.bones)
|
|
|
|
|
{
|
|
|
|
|
if (bone.Parent == null)
|
2019-06-22 00:18:22 +02:00
|
|
|
|
SkeletonWrapper.Nodes.Add(bone);
|
2019-06-21 00:01:06 +02:00
|
|
|
|
}
|
2019-06-20 23:20:06 +02:00
|
|
|
|
}
|
2019-06-21 00:01:06 +02:00
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
TreeNode MaterialFolderWrapper = new TreeNode("Materials");
|
|
|
|
|
Root.Nodes.Add(MaterialFolderWrapper);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < Materials.Count; i++)
|
|
|
|
|
{
|
2019-06-22 04:24:33 +02:00
|
|
|
|
GFBMaterial mat = new GFBMaterial(Root, Materials[i]);
|
2019-06-22 00:18:22 +02:00
|
|
|
|
mat.Text = Materials[i].Name;
|
|
|
|
|
|
|
|
|
|
int textureUnit = 1;
|
|
|
|
|
foreach (var textureMap in Materials[i].TextureMaps)
|
|
|
|
|
{
|
|
|
|
|
textureMap.Name = TextureMaps[(int)textureMap.Index];
|
|
|
|
|
|
|
|
|
|
STGenericMatTexture matTexture = new STGenericMatTexture();
|
|
|
|
|
matTexture.Name = textureMap.Name;
|
|
|
|
|
matTexture.textureUnit = textureUnit++;
|
2019-06-22 04:24:33 +02:00
|
|
|
|
matTexture.wrapModeS = 1;
|
2019-06-22 00:18:22 +02:00
|
|
|
|
matTexture.wrapModeT = 0;
|
|
|
|
|
|
|
|
|
|
if (textureMap.Effect == "Col0Tex")
|
|
|
|
|
{
|
|
|
|
|
matTexture.Type = STGenericMatTexture.TextureType.Diffuse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mat.TextureMaps.Add(matTexture);
|
|
|
|
|
|
|
|
|
|
if (textureMap.Effect != string.Empty)
|
|
|
|
|
mat.Nodes.Add($"{textureMap.Name} ({textureMap.Effect})");
|
|
|
|
|
else
|
|
|
|
|
mat.Nodes.Add($"{textureMap.Name}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GenericMaterials.Add(mat);
|
|
|
|
|
MaterialFolderWrapper.Nodes.Add(mat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TreeNode VisualGroupWrapper = new TreeNode("Visual Groups");
|
|
|
|
|
Root.Nodes.Add(VisualGroupWrapper);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < VisualGroups.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
GFBMesh mesh = new GFBMesh(Root);
|
|
|
|
|
mesh.Checked = true;
|
|
|
|
|
mesh.ImageKey = "model";
|
|
|
|
|
mesh.SelectedImageKey = "model";
|
|
|
|
|
|
|
|
|
|
mesh.BoneIndex = (int)VisualGroups[i].BoneIndex;
|
2019-06-23 00:45:43 +02:00
|
|
|
|
mesh.Text = Skeleton.bones[(int)VisualGroups[i].MeshIndex].Text;
|
2019-06-22 00:18:22 +02:00
|
|
|
|
Root.Renderer.Meshes.Add(mesh);
|
|
|
|
|
|
|
|
|
|
var Buffer = VertexBuffers[i];
|
|
|
|
|
for (int v= 0; v < Buffer.Positions.Count; v++)
|
|
|
|
|
{
|
|
|
|
|
Vertex vertex = new Vertex();
|
|
|
|
|
vertex.pos = Buffer.Positions[v];
|
|
|
|
|
|
|
|
|
|
if (Buffer.Normals.Count > 0)
|
|
|
|
|
vertex.nrm = Buffer.Normals[v];
|
|
|
|
|
if (Buffer.TexCoord1.Count > 0)
|
|
|
|
|
vertex.uv0 = Buffer.TexCoord1[v];
|
|
|
|
|
if (Buffer.TexCoord2.Count > 0)
|
|
|
|
|
vertex.uv1 = Buffer.TexCoord2[v];
|
|
|
|
|
if (Buffer.TexCoord3.Count > 0)
|
|
|
|
|
vertex.uv2 = Buffer.TexCoord3[v];
|
|
|
|
|
if (Buffer.Weights.Count > 0)
|
|
|
|
|
vertex.boneWeights = new List<float>(Buffer.Weights[v]);
|
|
|
|
|
if (Buffer.BoneIndex.Count > 0)
|
|
|
|
|
vertex.boneIds = new List<int>(Buffer.BoneIndex[v]);
|
|
|
|
|
if (Buffer.Colors1.Count > 0)
|
|
|
|
|
vertex.col = Buffer.Colors1[v];
|
|
|
|
|
if (Buffer.Binormals.Count > 0)
|
|
|
|
|
vertex.bitan = Buffer.Binormals[v];
|
|
|
|
|
|
|
|
|
|
mesh.vertices.Add(vertex);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 15:20:08 +02:00
|
|
|
|
mesh.FlipUvsVertical();
|
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
int polyIndex = 0;
|
|
|
|
|
foreach (var group in Buffer.PolygonGroups)
|
|
|
|
|
{
|
|
|
|
|
TreeNode polyWrapper = new TreeNode($"Polygon Group {polyIndex++}");
|
|
|
|
|
polyWrapper.ImageKey = "mesh";
|
|
|
|
|
polyWrapper.SelectedImageKey = "mesh";
|
|
|
|
|
|
|
|
|
|
var polygonGroup = new STGenericPolygonGroup();
|
|
|
|
|
polygonGroup.faces = group.Faces.ToList();
|
|
|
|
|
polygonGroup.MaterialIndex = group.MaterialID;
|
|
|
|
|
mesh.PolygonGroups.Add(polygonGroup);
|
|
|
|
|
|
|
|
|
|
mesh.Nodes.Add(polyWrapper);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VisualGroupWrapper.Nodes.Add(mesh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-06-21 00:01:06 +02:00
|
|
|
|
Skeleton.update();
|
|
|
|
|
Skeleton.reset();
|
2019-06-13 23:31:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Write(FileWriter writer)
|
|
|
|
|
{
|
|
|
|
|
writer.Write(Version);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
public class VisGroup
|
|
|
|
|
{
|
|
|
|
|
public Vector3 BoundingBoxMax = new Vector3(0);
|
|
|
|
|
public Vector3 BoundingBoxMin = new Vector3(0);
|
|
|
|
|
|
|
|
|
|
public uint BoneIndex { get; set; }
|
2019-06-23 00:45:43 +02:00
|
|
|
|
public uint MeshIndex { get; set; }
|
2019-06-22 00:18:22 +02:00
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
long DataPosition = reader.Position;
|
|
|
|
|
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(DataOffset);
|
|
|
|
|
long InfoPosition = reader.Position;
|
|
|
|
|
|
|
|
|
|
int InfoOffset = reader.ReadInt32();
|
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - InfoOffset);
|
|
|
|
|
ushort HeaderLength = reader.ReadUInt16();
|
|
|
|
|
ushort VisBonePosition = 0;
|
2019-06-23 00:45:43 +02:00
|
|
|
|
ushort VisMeshPosition = 0;
|
2019-06-22 00:18:22 +02:00
|
|
|
|
ushort Unknown2Position = 0;
|
|
|
|
|
ushort VisBoundsPosition = 0;
|
|
|
|
|
ushort Unknown3Position = 0;
|
|
|
|
|
|
|
|
|
|
if (HeaderLength == 0x0A)
|
|
|
|
|
{
|
|
|
|
|
VisBonePosition = reader.ReadUInt16();
|
2019-06-23 00:45:43 +02:00
|
|
|
|
VisMeshPosition = reader.ReadUInt16();
|
2019-06-22 00:18:22 +02:00
|
|
|
|
VisBoundsPosition = reader.ReadUInt16();
|
2019-06-23 00:45:43 +02:00
|
|
|
|
Unknown2Position = reader.ReadUInt16();
|
2019-06-22 00:18:22 +02:00
|
|
|
|
}
|
|
|
|
|
else if (HeaderLength == 0x0C)
|
|
|
|
|
{
|
|
|
|
|
VisBonePosition = reader.ReadUInt16();
|
2019-06-23 00:45:43 +02:00
|
|
|
|
VisMeshPosition = reader.ReadUInt16();
|
2019-06-22 00:18:22 +02:00
|
|
|
|
VisBoundsPosition = reader.ReadUInt16();
|
2019-06-23 00:45:43 +02:00
|
|
|
|
Unknown2Position = reader.ReadUInt16();
|
2019-06-22 00:18:22 +02:00
|
|
|
|
Unknown3Position = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unexpected Header Length! " + HeaderLength);
|
|
|
|
|
|
|
|
|
|
if (VisBoundsPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + VisBoundsPosition);
|
|
|
|
|
BoundingBoxMin = reader.ReadVec3();
|
|
|
|
|
BoundingBoxMax = reader.ReadVec3();
|
|
|
|
|
}
|
2019-06-23 00:45:43 +02:00
|
|
|
|
|
|
|
|
|
if (VisMeshPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + VisMeshPosition);
|
|
|
|
|
MeshIndex = reader.ReadUInt32();
|
|
|
|
|
}
|
2019-06-22 00:18:22 +02:00
|
|
|
|
|
|
|
|
|
if (VisBonePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + VisBonePosition);
|
|
|
|
|
BoneIndex = reader.ReadUInt32();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class MaterialShaderData
|
|
|
|
|
{
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
public string ShaderName { get; set; }
|
|
|
|
|
|
|
|
|
|
public List<TextureMap> TextureMaps = new List<TextureMap>();
|
|
|
|
|
|
2019-06-22 04:24:33 +02:00
|
|
|
|
public Dictionary<string, SwitchParam> SwitchParams = new Dictionary<string, SwitchParam>();
|
|
|
|
|
public Dictionary<string, ValueParam> ValueParams = new Dictionary<string, ValueParam>();
|
|
|
|
|
public Dictionary<string, ColorParam> ColorParams = new Dictionary<string, ColorParam>();
|
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
long DataPosition = reader.Position;
|
|
|
|
|
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(DataOffset);
|
|
|
|
|
long InfoPosition = reader.Position;
|
|
|
|
|
|
|
|
|
|
int InfoOffset = reader.ReadInt32();
|
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - InfoOffset);
|
|
|
|
|
ushort HeaderLength = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderPropertyPosition = reader.ReadUInt16();
|
|
|
|
|
ushort MaterialStringNamePosition = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderStringNamePosition = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown1Position = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown2Position = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown3Position = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParam1Position = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParam2Position = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParam3Position = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParam4Position = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParam5Position = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParam6Position = reader.ReadUInt16();
|
|
|
|
|
ushort TextureMapsPosition = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParamAPosition = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParamBPosition = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderParamCPosition = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown4Position = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown5Position = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown6Position = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown7Position = reader.ReadUInt16();
|
|
|
|
|
ushort Unknown8Position = reader.ReadUInt16();
|
|
|
|
|
ushort ShaderProperty2Position = reader.ReadUInt16();
|
|
|
|
|
|
|
|
|
|
if (MaterialStringNamePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + MaterialStringNamePosition);
|
|
|
|
|
Name = reader.ReadNameOffset(true, typeof(uint), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ShaderStringNamePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + ShaderStringNamePosition);
|
|
|
|
|
ShaderName = reader.ReadNameOffset(true, typeof(uint), true);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 04:24:33 +02:00
|
|
|
|
if (ShaderParamAPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + ShaderParamAPosition);
|
|
|
|
|
var ParamOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
reader.SeekBegin(ParamOffset);
|
|
|
|
|
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
SwitchParam param = new SwitchParam();
|
|
|
|
|
param.ReadParam(reader);
|
|
|
|
|
SwitchParams.Add(param.Name, param);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ShaderParamBPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + ShaderParamBPosition);
|
|
|
|
|
var ParamOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
reader.SeekBegin(ParamOffset);
|
|
|
|
|
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
ValueParam param = new ValueParam();
|
|
|
|
|
param.ReadParam(reader);
|
|
|
|
|
ValueParams.Add(param.Name, param);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ShaderParamCPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + ShaderParamCPosition);
|
|
|
|
|
var ParamOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
reader.SeekBegin(ParamOffset);
|
|
|
|
|
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
ColorParam param = new ColorParam();
|
|
|
|
|
param.ReadParam(reader);
|
|
|
|
|
ColorParams.Add(param.Name, param);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
if (TextureMapsPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + TextureMapsPosition);
|
|
|
|
|
var TextureMapOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
reader.SeekBegin(TextureMapOffset);
|
|
|
|
|
|
|
|
|
|
uint Count = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
TextureMap textureMap = new TextureMap();
|
|
|
|
|
textureMap.Read(reader);
|
|
|
|
|
TextureMaps.Add(textureMap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 04:24:33 +02:00
|
|
|
|
public class ColorParam : BaseParam
|
|
|
|
|
{
|
|
|
|
|
public void ReadParam(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
base.Read(reader);
|
|
|
|
|
|
|
|
|
|
if (ValuePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + ValuePosition);
|
|
|
|
|
if (Format == 4)
|
|
|
|
|
Value = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
|
|
|
|
else if (Format == 8)
|
|
|
|
|
Value = new Vector3(reader.ReadUInt32(), reader.ReadUInt32(), reader.ReadUInt32());
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unknown format for switch param! " + Format);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Value = 0;
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"Param {Name} {Value}");
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ValueParam : BaseParam
|
|
|
|
|
{
|
|
|
|
|
public void ReadParam(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
base.Read(reader);
|
|
|
|
|
|
|
|
|
|
if (ValuePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + ValuePosition);
|
|
|
|
|
if (Format == 4)
|
|
|
|
|
Value = reader.ReadUInt32();
|
|
|
|
|
else if (Format == 8)
|
|
|
|
|
Value = reader.ReadSingle();
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unknown format for switch param! " + Format);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Value = 0;
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class SwitchParam : BaseParam
|
|
|
|
|
{
|
|
|
|
|
public void ReadParam(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
base.Read(reader);
|
|
|
|
|
|
|
|
|
|
if (ValuePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + ValuePosition);
|
|
|
|
|
if (Format == 4)
|
|
|
|
|
Value = (reader.ReadByte() == 1);
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unknown format for switch param! " + Format);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Value = false;
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"Param {Name} {Value}");
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class BaseParam
|
|
|
|
|
{
|
|
|
|
|
public string Effect { get; set; }
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
|
|
|
|
public uint Index { get; set; } = 0;
|
|
|
|
|
|
|
|
|
|
public uint Format { get; set; }
|
|
|
|
|
|
|
|
|
|
public object Value { get; set; }
|
|
|
|
|
|
|
|
|
|
internal long DataPosition;
|
|
|
|
|
internal long InfoPosition;
|
|
|
|
|
|
|
|
|
|
internal ushort NamePosition;
|
|
|
|
|
internal ushort FormatPosition;
|
|
|
|
|
internal ushort ValuePosition;
|
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
DataPosition = reader.Position;
|
|
|
|
|
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(DataOffset);
|
|
|
|
|
InfoPosition = reader.Position;
|
|
|
|
|
int InfoOffset = reader.ReadInt32();
|
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - InfoOffset);
|
|
|
|
|
ushort HeaderSize = reader.ReadUInt16();
|
|
|
|
|
NamePosition = 0;
|
|
|
|
|
FormatPosition = 0;
|
|
|
|
|
ValuePosition = 0;
|
|
|
|
|
|
|
|
|
|
if (HeaderSize == 0x06)
|
|
|
|
|
{
|
|
|
|
|
NamePosition = reader.ReadUInt16();
|
|
|
|
|
FormatPosition = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
else if (HeaderSize == 0x08)
|
|
|
|
|
{
|
|
|
|
|
NamePosition = reader.ReadUInt16();
|
|
|
|
|
FormatPosition = reader.ReadUInt16();
|
|
|
|
|
ValuePosition = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unexpected header size! " + HeaderSize);
|
|
|
|
|
|
|
|
|
|
if (NamePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + NamePosition);
|
|
|
|
|
uint NameLength = reader.ReadUInt32();
|
|
|
|
|
Name = reader.ReadString((int)NameLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FormatPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + FormatPosition);
|
|
|
|
|
Format = reader.ReadUInt32();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 00:18:22 +02:00
|
|
|
|
public class TextureMap
|
|
|
|
|
{
|
|
|
|
|
public string Effect { get; set; }
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
|
|
|
|
public uint Index { get; set; } = 0;
|
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
long DataPosition = reader.Position;
|
|
|
|
|
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(DataOffset);
|
|
|
|
|
long InfoPosition = reader.Position;
|
|
|
|
|
int InfoOffset = reader.ReadInt32();
|
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - InfoOffset);
|
|
|
|
|
ushort HeaderSize = reader.ReadUInt16();
|
|
|
|
|
ushort EffectPosition = 0;
|
|
|
|
|
ushort UnknownPosition = 0;
|
|
|
|
|
ushort IdPosition = 0;
|
|
|
|
|
ushort UnknownPosition2 = 0;
|
|
|
|
|
|
|
|
|
|
if (HeaderSize == 0x0A)
|
|
|
|
|
{
|
|
|
|
|
EffectPosition = reader.ReadUInt16();
|
|
|
|
|
UnknownPosition = reader.ReadUInt16();
|
|
|
|
|
IdPosition = reader.ReadUInt16();
|
|
|
|
|
UnknownPosition2 = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unexpected header size! " + HeaderSize);
|
|
|
|
|
|
|
|
|
|
if (EffectPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + EffectPosition);
|
|
|
|
|
uint NameLength = reader.ReadUInt32();
|
|
|
|
|
Effect = reader.ReadString((int)NameLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IdPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + IdPosition);
|
|
|
|
|
Index = reader.ReadUInt32();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class VertexBuffer
|
|
|
|
|
{
|
|
|
|
|
public List<VertexAttribute> Attributes = new List<VertexAttribute>();
|
|
|
|
|
public List<PolygonGroup> PolygonGroups = new List<PolygonGroup>();
|
|
|
|
|
|
|
|
|
|
public List<Vector3> Positions = new List<Vector3>();
|
|
|
|
|
public List<Vector3> Normals = new List<Vector3>();
|
|
|
|
|
public List<Vector2> TexCoord1 = new List<Vector2>();
|
|
|
|
|
public List<Vector2> TexCoord2 = new List<Vector2>();
|
|
|
|
|
public List<Vector2> TexCoord3 = new List<Vector2>();
|
|
|
|
|
public List<Vector2> TexCoord4 = new List<Vector2>();
|
|
|
|
|
public List<int[]> BoneIndex = new List<int[]>();
|
|
|
|
|
public List<float[]> Weights = new List<float[]>();
|
|
|
|
|
public List<Vector4> Colors1 = new List<Vector4>();
|
|
|
|
|
public List<Vector4> Colors2 = new List<Vector4>();
|
|
|
|
|
public List<Vector4> Binormals = new List<Vector4>();
|
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
long DataPosition = reader.Position;
|
|
|
|
|
var VertexBufferDataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(VertexBufferDataOffset);
|
|
|
|
|
long InfoPosition = reader.Position;
|
|
|
|
|
int InfoOffset = reader.ReadInt32();
|
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - InfoOffset);
|
|
|
|
|
ushort InfoSize = reader.ReadUInt16();
|
|
|
|
|
ushort VerticesPosition = 0;
|
|
|
|
|
ushort FacesPosition = 0;
|
|
|
|
|
ushort AttributeInfoPosition = 0;
|
|
|
|
|
ushort BufferUnknownPosition = 0;
|
|
|
|
|
|
|
|
|
|
if (InfoSize == 0x0A)
|
|
|
|
|
{
|
|
|
|
|
BufferUnknownPosition = reader.ReadUInt16();
|
|
|
|
|
FacesPosition = reader.ReadUInt16();
|
|
|
|
|
AttributeInfoPosition = reader.ReadUInt16();
|
|
|
|
|
VerticesPosition = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unexpected Vertex Buffer Info Header Size! " + InfoSize);
|
|
|
|
|
|
|
|
|
|
uint VertBufferStride = 0;
|
|
|
|
|
|
|
|
|
|
if (AttributeInfoPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + AttributeInfoPosition);
|
|
|
|
|
var AttributeOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(AttributeOffset);
|
|
|
|
|
uint AttributeCount = reader.ReadUInt32();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < AttributeCount; i++)
|
|
|
|
|
{
|
|
|
|
|
var attribute = new VertexAttribute();
|
|
|
|
|
attribute.Read(reader);
|
|
|
|
|
Attributes.Add(attribute);
|
|
|
|
|
|
|
|
|
|
switch (attribute.Type)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferType.Position:
|
|
|
|
|
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
|
|
|
|
VertBufferStride += 0x08;
|
|
|
|
|
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
|
|
|
|
VertBufferStride += 0x0C;
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Normal:
|
|
|
|
|
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
|
|
|
|
VertBufferStride += 0x08;
|
|
|
|
|
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
|
|
|
|
VertBufferStride += 0x0C;
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Binormal:
|
|
|
|
|
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
|
|
|
|
VertBufferStride += 0x08;
|
|
|
|
|
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
|
|
|
|
VertBufferStride += 0x0C;
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord1:
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord2:
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord3:
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord4:
|
|
|
|
|
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
|
|
|
|
VertBufferStride += 0x04;
|
|
|
|
|
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
|
|
|
|
VertBufferStride += 0x08;
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Color1:
|
|
|
|
|
case VertexAttribute.BufferType.Color2:
|
|
|
|
|
if (attribute.Format == VertexAttribute.BufferFormat.Byte)
|
|
|
|
|
VertBufferStride += 0x04;
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.BoneIndex:
|
|
|
|
|
if (attribute.Format == VertexAttribute.BufferFormat.Short)
|
|
|
|
|
VertBufferStride += 0x08;
|
|
|
|
|
else if (attribute.Format == VertexAttribute.BufferFormat.Byte)
|
|
|
|
|
VertBufferStride += 0x04;
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Weights:
|
|
|
|
|
if (attribute.Format == VertexAttribute.BufferFormat.BytesAsFloat)
|
|
|
|
|
VertBufferStride += 0x04;
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"{attribute.Format} {attribute.Type} VertBufferStride {VertBufferStride}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FacesPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + FacesPosition);
|
|
|
|
|
var BufferOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(BufferOffset);
|
|
|
|
|
uint GroupCount = reader.ReadUInt32();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < GroupCount; i++)
|
|
|
|
|
{
|
|
|
|
|
var polygonGroup = new PolygonGroup();
|
|
|
|
|
polygonGroup.Read(reader);
|
|
|
|
|
PolygonGroups.Add(polygonGroup);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (VerticesPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + VerticesPosition);
|
|
|
|
|
var VertexOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(VertexOffset);
|
|
|
|
|
uint VertexBufferSize = reader.ReadUInt32();
|
|
|
|
|
|
|
|
|
|
for (int v = 0; v < VertexBufferSize / VertBufferStride; v++)
|
|
|
|
|
{
|
|
|
|
|
for (int att = 0; att < Attributes.Count; att++)
|
|
|
|
|
{
|
|
|
|
|
switch (Attributes[att].Type)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferType.Position:
|
|
|
|
|
var pos = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
Positions.Add(new Vector3(pos.X, pos.Y, pos.Z));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Normal:
|
|
|
|
|
var normal = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
Normals.Add(new Vector3(normal.X, normal.Y, normal.Z));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord1:
|
|
|
|
|
var texcoord1 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
TexCoord1.Add(new Vector2(texcoord1.X, texcoord1.Y));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord2:
|
|
|
|
|
var texcoord2 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
TexCoord2.Add(new Vector2(texcoord2.X, texcoord2.Y));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord3:
|
|
|
|
|
var texcoord3 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
TexCoord3.Add(new Vector2(texcoord3.X, texcoord3.Y));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.TexCoord4:
|
|
|
|
|
var texcoord4 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
TexCoord4.Add(new Vector2(texcoord4.X, texcoord4.Y));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Weights:
|
|
|
|
|
var weights = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
Weights.Add(new float[] { weights.X, weights.Y, weights.Z, weights.W });
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.BoneIndex:
|
|
|
|
|
var boneIndices = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
BoneIndex.Add(new int[] { (int)boneIndices.X, (int)boneIndices.Y, (int)boneIndices.Z, (int)boneIndices.W });
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Color1:
|
|
|
|
|
var colors1 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
Colors1.Add(new Vector4(colors1.X, colors1.Y, colors1.Z, colors1.W));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Color2:
|
|
|
|
|
var colors2 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
Colors2.Add(new Vector4(colors2.X, colors2.Y, colors2.Z, colors2.W));
|
|
|
|
|
break;
|
|
|
|
|
case VertexAttribute.BufferType.Binormal:
|
|
|
|
|
var binormals = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
|
|
|
|
Binormals.Add(new Vector4(binormals.X, binormals.Y, binormals.Z, binormals.W));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Vector4 ParseBuffer(FileReader reader, VertexAttribute.BufferFormat Format, VertexAttribute.BufferType AttributeType)
|
|
|
|
|
{
|
|
|
|
|
if (AttributeType == VertexAttribute.BufferType.Position)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferFormat.Float:
|
|
|
|
|
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), 0);
|
|
|
|
|
case VertexAttribute.BufferFormat.HalfFloat:
|
|
|
|
|
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(),
|
|
|
|
|
reader.ReadHalfSingle(), reader.ReadHalfSingle());
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (AttributeType == VertexAttribute.BufferType.Normal)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferFormat.Float:
|
|
|
|
|
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), 0);
|
|
|
|
|
case VertexAttribute.BufferFormat.HalfFloat:
|
|
|
|
|
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(),
|
|
|
|
|
reader.ReadHalfSingle(), reader.ReadHalfSingle());
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (AttributeType == VertexAttribute.BufferType.Binormal)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferFormat.Float:
|
|
|
|
|
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), 0);
|
|
|
|
|
case VertexAttribute.BufferFormat.HalfFloat:
|
|
|
|
|
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(),
|
|
|
|
|
reader.ReadHalfSingle(), reader.ReadHalfSingle());
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (AttributeType == VertexAttribute.BufferType.TexCoord1 ||
|
|
|
|
|
AttributeType == VertexAttribute.BufferType.TexCoord2 ||
|
|
|
|
|
AttributeType == VertexAttribute.BufferType.TexCoord3 ||
|
|
|
|
|
AttributeType == VertexAttribute.BufferType.TexCoord4)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferFormat.Float:
|
|
|
|
|
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), 0, 0);
|
|
|
|
|
case VertexAttribute.BufferFormat.HalfFloat:
|
|
|
|
|
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(), 0, 0);
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (AttributeType == VertexAttribute.BufferType.Color1 ||
|
|
|
|
|
AttributeType == VertexAttribute.BufferType.Color2)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferFormat.Byte:
|
|
|
|
|
return new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (AttributeType == VertexAttribute.BufferType.BoneIndex)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferFormat.Short:
|
|
|
|
|
return new Vector4(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
|
|
|
|
|
case VertexAttribute.BufferFormat.Byte:
|
|
|
|
|
return new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (AttributeType == VertexAttribute.BufferType.Weights)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
|
|
|
|
case VertexAttribute.BufferFormat.BytesAsFloat:
|
|
|
|
|
return new Vector4(reader.ReadByteAsFloat(), reader.ReadByteAsFloat(),
|
|
|
|
|
reader.ReadByteAsFloat(), reader.ReadByteAsFloat());
|
|
|
|
|
default:
|
|
|
|
|
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new Vector4(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Represents an offset which points to another
|
|
|
|
|
public class OffsetInfo
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class PolygonGroup
|
|
|
|
|
{
|
|
|
|
|
public int MaterialID { get; set; }
|
|
|
|
|
public int[] Faces { get; set; }
|
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
long DataPosition = reader.Position;
|
|
|
|
|
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(DataOffset);
|
|
|
|
|
long InfoPosition = reader.Position;
|
|
|
|
|
|
|
|
|
|
int InfoOffset = reader.ReadInt32();
|
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - InfoOffset);
|
|
|
|
|
ushort PolygonHeaderSize = reader.ReadUInt16();
|
|
|
|
|
ushort PolygonStartPosition = 0;
|
|
|
|
|
ushort PolgonMaterialId = 0;
|
|
|
|
|
ushort PolygonUnknown = 0;
|
|
|
|
|
|
|
|
|
|
if (PolygonHeaderSize == 0x08)
|
|
|
|
|
{
|
|
|
|
|
PolygonStartPosition = reader.ReadUInt16();
|
|
|
|
|
PolgonMaterialId = reader.ReadUInt16();
|
|
|
|
|
PolygonUnknown = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unexpected Polygon Buffer Info Header Size! " + PolygonHeaderSize);
|
|
|
|
|
|
|
|
|
|
if (PolgonMaterialId != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + PolgonMaterialId);
|
|
|
|
|
MaterialID = reader.ReadInt32();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PolygonStartPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + PolygonStartPosition);
|
|
|
|
|
uint FaceCount = reader.ReadUInt32();
|
|
|
|
|
Faces = new int[FaceCount];
|
|
|
|
|
for (int i = 0; i < FaceCount; i++)
|
|
|
|
|
Faces[i] = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class VertexAttribute
|
|
|
|
|
{
|
|
|
|
|
public BufferFormat Format { get; set; } = BufferFormat.Float;
|
|
|
|
|
public BufferType Type { get; set; } = BufferType.Position;
|
|
|
|
|
|
|
|
|
|
public enum BufferType
|
|
|
|
|
{
|
|
|
|
|
Position = 0,
|
|
|
|
|
Normal = 1,
|
|
|
|
|
Binormal = 2,
|
|
|
|
|
TexCoord1 = 3,
|
|
|
|
|
TexCoord2 = 4,
|
|
|
|
|
TexCoord3 = 5,
|
|
|
|
|
TexCoord4 = 6,
|
|
|
|
|
Color1 = 7,
|
|
|
|
|
Color2 = 8,
|
|
|
|
|
BoneIndex = 11,
|
|
|
|
|
Weights = 12,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public enum BufferFormat
|
|
|
|
|
{
|
|
|
|
|
Float = 0,
|
|
|
|
|
HalfFloat = 1,
|
|
|
|
|
Byte = 3,
|
|
|
|
|
Short = 5,
|
|
|
|
|
BytesAsFloat = 8,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
long DataPosition = reader.Position;
|
|
|
|
|
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(DataOffset);
|
|
|
|
|
long InfoPosition = reader.Position;
|
|
|
|
|
int InfoOffset = reader.ReadInt32();
|
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - InfoOffset);
|
|
|
|
|
ushort LayoutHeaderLength = reader.ReadUInt16();
|
|
|
|
|
ushort LayoutSizePosition = 0;
|
|
|
|
|
ushort LayoutTypePosition = 0;
|
|
|
|
|
ushort LayoutFormatPosition = 0;
|
|
|
|
|
ushort LayoutUnknownPosition = 0;
|
|
|
|
|
|
|
|
|
|
if (LayoutHeaderLength == 0x0A)
|
|
|
|
|
{
|
|
|
|
|
LayoutSizePosition = reader.ReadUInt16();
|
|
|
|
|
LayoutTypePosition = reader.ReadUInt16();
|
|
|
|
|
LayoutFormatPosition = reader.ReadUInt16();
|
|
|
|
|
LayoutUnknownPosition = reader.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new Exception("Unexpected Attribute Layout Header Size! " + LayoutHeaderLength);
|
|
|
|
|
|
|
|
|
|
if (LayoutFormatPosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + LayoutFormatPosition);
|
|
|
|
|
Format = reader.ReadEnum<BufferFormat>(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (LayoutTypePosition != 0)
|
|
|
|
|
{
|
|
|
|
|
reader.SeekBegin(InfoPosition + LayoutTypePosition);
|
|
|
|
|
Type = reader.ReadEnum<BufferType>(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Seek back to next in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-20 23:20:06 +02:00
|
|
|
|
public class Bone : STBone
|
|
|
|
|
{
|
|
|
|
|
internal BoneInfo BoneInfo { get; set; }
|
|
|
|
|
|
|
|
|
|
public Bone(STSkeleton skeleton) : base(skeleton) { }
|
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
long DataPosition = reader.Position;
|
|
|
|
|
var BoneDataOffset = reader.ReadOffset(true, typeof(uint));
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(BoneDataOffset);
|
|
|
|
|
long InfoPosition = reader.Position;
|
|
|
|
|
|
2019-06-21 00:01:06 +02:00
|
|
|
|
int BoneInfoOffset = reader.ReadInt32();
|
2019-06-20 23:20:06 +02:00
|
|
|
|
|
|
|
|
|
//Read the info section for position data
|
|
|
|
|
reader.SeekBegin(InfoPosition - BoneInfoOffset);
|
|
|
|
|
|
|
|
|
|
BoneInfo = new BoneInfo();
|
|
|
|
|
BoneInfo.Read(reader);
|
|
|
|
|
|
2019-06-21 00:01:06 +02:00
|
|
|
|
RotationType = BoneRotationType.Euler;
|
|
|
|
|
Checked = true;
|
|
|
|
|
|
2019-06-20 23:20:06 +02:00
|
|
|
|
if (BoneInfo.NamePosition != 0)
|
|
|
|
|
{
|
2019-06-21 00:01:06 +02:00
|
|
|
|
reader.SeekBegin(InfoPosition + BoneInfo.NamePosition);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
uint NameLength = reader.ReadUInt32();
|
|
|
|
|
Text = reader.ReadString((int)NameLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BoneInfo.RotationPosition != 0)
|
|
|
|
|
{
|
2019-06-21 00:01:06 +02:00
|
|
|
|
reader.SeekBegin(InfoPosition + BoneInfo.RotationPosition);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
float RotationX = reader.ReadSingle();
|
|
|
|
|
float RotationY = reader.ReadSingle();
|
|
|
|
|
float RotationZ = reader.ReadSingle();
|
|
|
|
|
rotation = new float[] { RotationX,RotationY, RotationZ };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BoneInfo.TranslationPosition != 0)
|
|
|
|
|
{
|
2019-06-21 00:01:06 +02:00
|
|
|
|
reader.SeekBegin(InfoPosition + BoneInfo.TranslationPosition);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
float TranslateX = reader.ReadSingle();
|
|
|
|
|
float TranslateY = reader.ReadSingle();
|
|
|
|
|
float TranslateZ = reader.ReadSingle();
|
|
|
|
|
position = new float[] { TranslateX, TranslateY, TranslateZ };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BoneInfo.ScalePosition != 0)
|
|
|
|
|
{
|
2019-06-21 00:01:06 +02:00
|
|
|
|
reader.SeekBegin(InfoPosition + BoneInfo.ScalePosition);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
float ScaleX = reader.ReadSingle();
|
|
|
|
|
float ScaleY = reader.ReadSingle();
|
|
|
|
|
float ScaleZ = reader.ReadSingle();
|
|
|
|
|
scale = new float[] { ScaleX, ScaleY, ScaleZ };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BoneInfo.ParentPosition != 0)
|
|
|
|
|
{
|
2019-06-21 00:01:06 +02:00
|
|
|
|
reader.SeekBegin(InfoPosition + BoneInfo.ParentPosition);
|
2019-06-20 23:20:06 +02:00
|
|
|
|
parentIndex = reader.ReadInt32();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Seek back to next bone in array
|
|
|
|
|
reader.SeekBegin(DataPosition + sizeof(uint));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//A section that stores position info for bone data
|
|
|
|
|
public class BoneInfo
|
2019-06-13 23:31:35 +02:00
|
|
|
|
{
|
2019-06-20 23:20:06 +02:00
|
|
|
|
internal ushort SectionSize { get; set; }
|
|
|
|
|
internal ushort NamePosition { get; set; }
|
|
|
|
|
internal ushort UnknownPosition { get; set; }
|
|
|
|
|
internal ushort Unknown2Position { get; set; }
|
|
|
|
|
internal ushort ParentPosition { get; set; }
|
|
|
|
|
internal ushort Unknown3Position { get; set; }
|
2019-06-21 00:01:06 +02:00
|
|
|
|
internal ushort IsVisiblePosition { get; set; }
|
2019-06-20 23:20:06 +02:00
|
|
|
|
internal ushort ScalePosition { get; set; }
|
|
|
|
|
internal ushort RotationPosition { get; set; }
|
|
|
|
|
internal ushort TranslationPosition { get; set; }
|
|
|
|
|
internal ushort Unknown4Position { get; set; }
|
|
|
|
|
internal ushort Unknown5Position { get; set; }
|
2019-06-13 23:31:35 +02:00
|
|
|
|
|
2019-06-20 23:20:06 +02:00
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
SectionSize = reader.ReadUInt16();
|
|
|
|
|
NamePosition = reader.ReadUInt16();
|
|
|
|
|
UnknownPosition = reader.ReadUInt16();
|
|
|
|
|
Unknown2Position = reader.ReadUInt16();
|
|
|
|
|
ParentPosition = reader.ReadUInt16();
|
|
|
|
|
Unknown3Position = reader.ReadUInt16(); //Padding
|
2019-06-21 00:01:06 +02:00
|
|
|
|
IsVisiblePosition = reader.ReadUInt16(); //Points to byte. 0 or 1 for visibilty
|
2019-06-20 23:20:06 +02:00
|
|
|
|
ScalePosition = reader.ReadUInt16();
|
|
|
|
|
RotationPosition = reader.ReadUInt16();
|
|
|
|
|
TranslationPosition = reader.ReadUInt16();
|
|
|
|
|
Unknown4Position = reader.ReadUInt16(); //Padding
|
|
|
|
|
Unknown5Position = reader.ReadUInt16(); //Padding
|
|
|
|
|
}
|
2019-06-13 23:31:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Material
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
2019-06-02 20:08:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|