-using System;\r
-using System.Collections.Generic;\r
-using System.IO;\r
-using System.Text;\r
-using System.ComponentModel;\r
-using Microsoft.DirectX;\r
-using Microsoft.DirectX.Direct3D;\r
-\r
-namespace Tso2MqoGui\r
-{\r
- public class TSOFile : TDCGFile\r
- {\r
- internal Dictionary<string, TSONode> nodemap;\r
- internal Dictionary<string, TSOTex> texturemap;\r
- internal TSONode[] nodes;\r
- internal TSOTex[] textures;\r
- internal TSOEffect[] effects;\r
- internal TSOMaterial[] materials;\r
- internal TSOMesh[] meshes;\r
-\r
- public TSOFile(string file) : base(file) {}\r
- public TSOFile(Stream s) : base(s) {}\r
- public TSOFile(BinaryReader r) : base(r) {}\r
-\r
- public void SaveTo(string file)\r
- {\r
- }\r
-\r
- [System.Diagnostics.Conditional("DEBUG_DETAIL")]\r
- public static void WriteLine(string s)\r
- {\r
- System.Diagnostics.Debug.WriteLine(s);\r
- }\r
-\r
- public void ReadAll()\r
- {\r
- byte[] magic = r.ReadBytes(4);\r
-\r
- if(magic[0] != (byte)'T'\r
- || magic[1] != (byte)'S'\r
- || magic[2] != (byte)'O'\r
- || magic[3] != (byte)'1')\r
- throw new Exception("File is not TSO");\r
-\r
- //----- \83m\81[\83h -------------------------------------------------\r
- nodemap = new Dictionary<string, TSONode>();\r
- int count = r.ReadInt32();\r
- nodes = new TSONode[count];\r
-\r
- for(int i= 0; i < count; ++i)\r
- {\r
- nodes[i] = new TSONode();\r
- nodes[i].id = i;\r
- nodes[i].name = ReadString();\r
- nodes[i].sname = nodes[i].name.Substring(nodes[i].name.LastIndexOf('|')+1);\r
- nodemap.Add(nodes[i].name, nodes[i]);\r
-\r
- WriteLine(i+ ": " + nodes[i].name);\r
- }\r
-\r
- for(int i= 0; i < count; ++i)\r
- {\r
- int index = nodes[i].name.LastIndexOf('|');\r
-\r
- if(index <= 0)\r
- continue;\r
-\r
- string pname = nodes[i].name.Substring(0, index);\r
- WriteLine(pname);\r
- nodes[i].parent = nodemap[pname];\r
- nodes[i].parent.children.Add(nodes[i]);\r
- }\r
-\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
-\r
- count = r.ReadInt32();\r
-\r
- // Node Matrix\r
- for(int i= 0; i < count; ++i)\r
- {\r
- nodes[i].matrix = ReadMatrix();\r
- }\r
-\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
-\r
- //----- \83e\83N\83X\83`\83\83 ---------------------------------------------\r
- count = r.ReadInt32();\r
- textures = new TSOTex[count];\r
- texturemap = new Dictionary<string, TSOTex>();\r
-\r
- for(int i= 0; i < count; ++i)\r
- {\r
- textures[i] = new TSOTex();\r
- textures[i].id = i;\r
- textures[i].name = ReadString();\r
- textures[i].file = ReadString();\r
- textures[i].width = r.ReadInt32();\r
- textures[i].height = r.ReadInt32();\r
- textures[i].depth = r.ReadInt32();\r
- textures[i].data = r.ReadBytes(textures[i].width * textures[i].height * textures[i].depth);\r
- texturemap.Add(textures[i].name, textures[i]);\r
-\r
- for(int j= 0; j < textures[i].data.Length; j+=4)\r
- {\r
- byte tmp = textures[i].data[j+2];\r
- textures[i].data[j+2]= textures[i].data[j+0];\r
- textures[i].data[j+0]= tmp;\r
- }\r
-\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
- }\r
-\r
- //----- \83G\83t\83F\83N\83g ---------------------------------------------\r
- count = r.ReadInt32();\r
- effects = new TSOEffect[count];\r
-\r
- for(int i= 0; i < count; ++i)\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- effects[i] = new TSOEffect();\r
- effects[i].name = ReadString();\r
- effects[i].line = r.ReadInt32();\r
-\r
- for(int j= 0; j < effects[i].line; ++j)\r
- sb.Append(ReadString()).Append('\n');\r
-\r
- effects[i].code = sb.ToString();\r
-\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
- }\r
-\r
- //----- \83}\83e\83\8a\83A\83\8b ---------------------------------------------\r
- count = r.ReadInt32();\r
- materials = new TSOMaterial[count];\r
-\r
- for(int i= 0; i < count; ++i)\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- materials[i] = new TSOMaterial();\r
- materials[i].id = i;\r
- materials[i].name = ReadString();\r
- materials[i].file = ReadString();\r
- materials[i].line = r.ReadInt32();\r
-\r
- for(int j= 0; j < materials[i].line; ++j)\r
- sb.Append(ReadString()).Append('\n');\r
-\r
- materials[i].code = sb.ToString();\r
- materials[i].ParseParameters();\r
-\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
- }\r
-\r
- //----- \83\81\83b\83V\83\85 -----------------------------------------------\r
- count = r.ReadInt32();\r
- meshes = new TSOMesh[count];\r
- int check = 0;\r
-#if true\r
- bool debug = false;\r
-#endif\r
- for(int i= 0; i < count; ++i)\r
- {\r
- meshes[i] = new TSOMesh();\r
- meshes[i].file = this;\r
- meshes[i].name = ReadString();\r
- meshes[i].matrix = ReadMatrix();\r
- meshes[i].effect = r.ReadInt32();\r
- meshes[i].numsubs = r.ReadInt32();\r
- meshes[i].sub = new TSOSubMesh[meshes[i].numsubs];\r
-\r
- for(int j= 0; j < meshes[i].numsubs; ++j)\r
- {\r
- meshes[i].sub[j] = new TSOSubMesh();\r
- meshes[i].sub[j].owner = meshes[i];\r
- meshes[i].sub[j].spec = r.ReadInt32();\r
- meshes[i].sub[j].numbones = r.ReadInt32();\r
- meshes[i].sub[j].bones = new int[meshes[i].sub[j].numbones];\r
-\r
- meshes[i].sub[j].ink = materials[meshes[i].sub[j].spec].technique.ToUpper().IndexOf("INKOFF") < 0;\r
- //meshes[i].sub[j].shadow = specs[meshes[i].sub[j].spec].technique.ToUpper().IndexOf(Shadow\r
-\r
- for(int k= 0; k < meshes[i].sub[j].numbones; ++k)\r
- meshes[i].sub[j].bones[k] = r.ReadInt32();\r
-\r
- meshes[i].sub[j].numvertices= r.ReadInt32();\r
- Vertex[] v = new Vertex[meshes[i].sub[j].numvertices];\r
- meshes[i].sub[j].vertices= v;\r
-\r
- for(int k= 0; k < meshes[i].sub[j].numvertices; ++k)\r
- {\r
- if(debug)\r
- {\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
- ReadVertexDebug(ref v[k]);\r
- } else\r
- {\r
- ReadVertex(ref v[k]);\r
- }\r
- }\r
-\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
- System.Diagnostics.Debug.WriteLine(r.BaseStream.Position.ToString("X"));\r
-#if DEBUG\r
- if(r.BaseStream.Position == 0x61F94)\r
- debug = true;\r
-#endif\r
- }\r
- }\r
-\r
- WriteLine(r.BaseStream.Position.ToString("X"));\r
- WriteLine(check.ToString("X"));\r
-\r
- r.BaseStream.Dispose();\r
- }\r
- }\r
-\r
- public class TSONode\r
- {\r
- internal int id;\r
- internal string name;\r
- internal string sname;\r
- internal Matrix44 matrix;\r
- internal Matrix44 world;\r
- internal List<TSONode> children = new List<TSONode>();\r
- internal TSONode parent;\r
-\r
- [Category("General")] public int ID { get { return id; } }\r
- [Category("General")] public string Name { get { return name; } }\r
- [Category("General")] public string ShortName { get { return sname; } }\r
- [Category("Detail")] public Matrix44 Matrix { get { return matrix; } set { matrix= value; } }\r
- [Category("Detail")] public Matrix44 World { get { return world; } set { world = value; } }\r
-\r
- public override string ToString()\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- sb.Append("Name: ").AppendLine(name);\r
- sb.Append("Matrix: ").AppendLine(matrix.ToString());\r
- sb.Append("Children.Count: ").AppendLine(children.Count.ToString());\r
- return sb.ToString();\r
- }\r
- }\r
-\r
- public class TSOTex\r
- {\r
- internal int id;\r
- internal string name;\r
- internal string file;\r
- internal int width;\r
- internal int height;\r
- internal int depth;\r
- internal byte[] data;\r
-\r
- [Category("General")] public int ID { get { return id; } }\r
- [Category("General")] public string Name { get { return name; } }\r
- [Category("Detail")] public string File { get { return file; } set { file= value; } }\r
- [Category("Detail")] public int Width { get { return width; } }\r
- [Category("Detail")] public int Height { get { return height; } }\r
- [Category("Detail")] public int Depth { get { return depth; } }\r
-\r
- public override string ToString()\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- sb.Append("Name: ").AppendLine(name);\r
- sb.Append("File: ").AppendLine(file);\r
- sb.Append("Width: ").AppendLine(width.ToString());\r
- sb.Append("Height: ").AppendLine(height.ToString());\r
- sb.Append("Depth: ").AppendLine(depth.ToString());\r
- sb.Append("Data.Length: ").AppendLine(data.Length.ToString());\r
- return sb.ToString();\r
- }\r
- }\r
-\r
- public class TSOEffect\r
- {\r
- internal string name;\r
- internal int line;\r
- internal string code;\r
-\r
- [Category("General")] public string Name { get { return name; } }\r
- [Category("Detail")] public string Code { get { return code; } set { code= value; } }\r
-\r
- public override string ToString()\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- sb.Append("Name: ").AppendLine(name);\r
- sb.Append("Line: ").AppendLine(line.ToString());\r
- sb.AppendLine("Code:").AppendLine(code);\r
- return sb.ToString();\r
- }\r
- }\r
-\r
- public class TSOParameter\r
- {\r
- public string Name;\r
- public string Type;\r
- public string Value;\r
-\r
- public TSOParameter(string type, string name, string value)\r
- {\r
- Name = name;\r
- Type = type;\r
- Value = value;\r
- }\r
-\r
- public override string ToString()\r
- {\r
-#if true\r
- return Type + " " + Name + " = " + Value;\r
-#else\r
- switch(Type)\r
- {\r
- case "string": return Type + " " + Name + " = \"" + Value + "\"";\r
- case "float": return Type + " " + Name + " = [" + Value + "]";\r
- case "float4": return Type + " " + Name + " = [" + Value + "]";\r
- default: return Type + " " + Name + " = " + Value;\r
- }\r
-#endif\r
- }\r
- }\r
-\r
- public class TSOMaterialCode : Dictionary<string, TSOParameter>\r
- {\r
-\r
- public TSOMaterialCode(string code)\r
- : this(code.Split('\r', '\n'))\r
- {\r
- }\r
-\r
- public string GetValue(string index)\r
- {\r
- return this[index].Value;\r
- }\r
-\r
- public void SetValue(string index, string value)\r
- {\r
- TSOParameter p = this[index];\r
- p.Value = value;\r
- }\r
- \r
- public TSOMaterialCode(string[] code)\r
- {\r
- foreach(string i in code)\r
- {\r
- try\r
- {\r
- int n1, n2;\r
-\r
- if((n1= i.IndexOf(' ')) < 0) continue;\r
- if((n2= i.IndexOf('=', n1+1)) < 0) continue;\r
-\r
- TSOParameter p = new TSOParameter(\r
- i.Substring(0, n1) .Trim(),\r
- i.Substring(n1, n2-n1).Trim(),\r
- i.Substring(n2+1) .Trim());\r
- TSOFile.WriteLine(p.ToString());\r
- Add(p.Name, p);\r
- } catch(Exception e)\r
- {\r
- System.Diagnostics.Debug.WriteLine(e);\r
- }\r
- }\r
- }\r
-\r
- public static TSOMaterialCode GenerateFromFile(string filename)\r
- {\r
- return new TSOMaterialCode(File.ReadAllLines(filename));\r
- }\r
- }\r
-\r
- public class TSOMaterial\r
- {\r
- internal int id;\r
- internal string name;\r
- internal string file;\r
- internal int line;\r
- internal string code;\r
- internal TSOMaterialCode codedata;\r
-\r
- internal string description; // = "TA ToonShader v0.50"\r
- internal string shader; // = "TAToonshade_050.cgfx"\r
- internal string technique; // = "ShadowOn"\r
- internal float lightDirX; // = [-0.00155681]\r
- internal float lightDirY; // = [-0.0582338]\r
- internal float lightDirZ; // = [-0.998302]\r
- internal float lightDirW; // = [0]\r
- internal Point4 shadowColor; // = [0, 0, 0, 1]\r
- internal string shadeTex; // = Ninjya_Ribbon_Toon_Tex\r
- internal float highLight; // = [0]\r
- internal float colorBlend; // = [10]\r
- internal float highLightBlend; // = [10]\r
- internal Point4 penColor; // = [0.166, 0.166, 0.166, 1]\r
- internal float ambient; // = [38]\r
- internal string colorTex; // = file24\r
- internal float thickness; // = [0.018]\r
- internal float shadeBlend; // = [10]\r
- internal float highLightPower; // = [100]\r
-\r
- [Category("General")] public int ID { get { return id; } }\r
- [Category("General")] public string Name { get { return name; } }\r
- [Category("Detail")] public string File { get { return file; } }\r
- [Category("Detail")] public string Code { get { return code; } set { code= value; } }\r
-\r
- [Category("Parameters")] public string Description { get { return description; } set { description = value; } }\r
- [Category("Parameters")] public string Shader { get { return shader; } set { shader = value; } }\r
- [Category("Parameters")] public string Technique { get { return technique; } set { technique = value; } }\r
- [Category("Parameters")] public float LightDirX { get { return lightDirX; } set { lightDirX = value; } }\r
- [Category("Parameters")] public float LightDirY { get { return lightDirY; } set { lightDirY = value; } }\r
- [Category("Parameters")] public float LightDirZ { get { return lightDirZ; } set { lightDirZ = value; } }\r
- [Category("Parameters")] public float LightDirW { get { return lightDirW; } set { lightDirW = value; } }\r
- [Category("Parameters")] public Point4 ShadowColor { get { return shadowColor; } set { shadowColor = value; } }\r
- [Category("Parameters")] public string ShadeTex { get { return shadeTex; } set { shadeTex = value; } }\r
- [Category("Parameters")] public float HighLight { get { return highLight; } set { highLight = value; } }\r
- [Category("Parameters")] public float ColorBlend { get { return colorBlend; } set { colorBlend = value; } }\r
- [Category("Parameters")] public float HighLightBlend { get { return highLightBlend; } set { highLightBlend= value; } }\r
- [Category("Parameters")] public Point4 PenColor { get { return penColor; } set { penColor = value; } }\r
- [Category("Parameters")] public float Ambient { get { return ambient; } set { ambient = value; } }\r
- [Category("Parameters")] public string ColorTex { get { return colorTex; } set { colorTex = value; } }\r
- [Category("Parameters")] public float Thickness { get { return thickness; } set { thickness = value; } }\r
- [Category("Parameters")] public float ShadeBlend { get { return shadeBlend; } set { shadeBlend = value; } }\r
- [Category("Parameters")] public float HighLightPower { get { return highLightPower; } set { highLightPower= value; } }\r
-\r
- public override string ToString()\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- sb.Append("Name: ").AppendLine(name);\r
- sb.Append("File: ").AppendLine(file);\r
- sb.Append("Line: ").AppendLine(line.ToString());\r
- sb.AppendLine("Code:").AppendLine(code);\r
-\r
- return sb.ToString();\r
- }\r
-\r
- public void ParseParameters()\r
- {\r
- codedata = new TSOMaterialCode(code);\r
-\r
- foreach(TSOParameter i in codedata.Values)\r
- SetValue(i.Type, i.Name, i.Value);\r
- }\r
-\r
- public void SetValue(string type, string name, string value)\r
- {\r
- switch(name)\r
- {\r
- case "description": description = GetString (value); break; // = "TA ToonShader v0.50"\r
- case "shader": shader = GetString (value); break; // = "TAToonshade_050.cgfx"\r
- case "technique": technique = GetString (value); break; // = "ShadowOn"\r
- case "LightDirX": lightDirX = GetFloat (value); break; // = [-0.00155681]\r
- case "LightDirY": lightDirY = GetFloat (value); break; // = [-0.0582338]\r
- case "LightDirZ": lightDirZ = GetFloat (value); break; // = [-0.998302]\r
- case "LightDirW": lightDirW = GetFloat (value); break; // = [0]\r
- case "ShadowColor": shadowColor = GetPoint4 (value); break; // = [0, 0, 0, 1]\r
- case "ShadeTex": shadeTex = GetTexture(value); break; // = Ninjya_Ribbon_Toon_Tex\r
- case "HighLight": highLight = GetFloat (value); break; // = [0]\r
- case "ColorBlend": colorBlend = GetFloat (value); break; // = [10]\r
- case "HighLightBlend": highLightBlend = GetFloat (value); break; // = [10]\r
- case "PenColor": penColor = GetPoint4 (value); break; // = [0.166, 0.166, 0.166, 1]\r
- case "Ambient": ambient = GetFloat (value); break; // = [38]\r
- case "ColorTex": colorTex = GetTexture(value); break; // = file24\r
- case "Thickness": thickness = GetFloat (value); break; // = [0.018]\r
- case "ShadeBlend": shadeBlend = GetFloat (value); break; // = [10]\r
- case "HighLightPower": highLightPower = GetFloat (value); break; // = [100]\r
- default:\r
- TSOFile.WriteLine("Unknown parameter. type=" + type + ", name=" + name + ", value=" + value);\r
- break;\r
- }\r
- }\r
-\r
- public string GetTexture(string value)\r
- {\r
- return value;\r
- }\r
-\r
- public string GetString(string value)\r
- {\r
- return value.Trim('"');\r
- }\r
-\r
- public float GetFloat(string value)\r
- {\r
- return float.Parse(value.Trim('[', ']', ' '));\r
- }\r
-\r
- public Point4 GetPoint4(string value)\r
- {\r
- string[] token = value.Trim('[', ']', ' ').Split(',');\r
- Point4 p = new Point4();\r
- p.X = float.Parse(token[0].Trim());\r
- p.Y = float.Parse(token[1].Trim());\r
- p.Z = float.Parse(token[2].Trim());\r
- p.W = float.Parse(token[3].Trim());\r
- return p;\r
- }\r
- }\r
-\r
- public class TSOMesh\r
- {\r
- internal TSOFile file;\r
- internal string name;\r
- internal Matrix44 matrix;\r
- internal int effect;\r
- internal int numsubs;\r
- internal TSOSubMesh[] sub;\r
-\r
- [Category("General")] public string Name { get { return name; } set { name= value; } }\r
- //[Category("Detail")] public int Effect { get { return name; } set { name= value; } }\r
- [Category("Detail")] public Matrix44 Matrix { get { return matrix; } set { matrix= value; } }\r
-\r
- public override string ToString()\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- sb.Append("Name: ").AppendLine(name);\r
- sb.Append("Matrix: ").AppendLine(matrix.ToString());\r
- sb.Append("Effect?: ").AppendLine(effect.ToString());\r
- sb.Append("NumSubs: ").AppendLine(numsubs.ToString());\r
- sb.Append("SubMesh.Count: ").AppendLine(sub.Length.ToString());\r
- return sb.ToString();\r
- }\r
- }\r
-\r
- public class TSOSubMesh\r
- {\r
- internal int spec;\r
- internal int numbones;\r
- internal int[] bones;\r
- internal int numvertices;\r
- internal Vertex[] vertices;\r
- internal TSOMesh owner;\r
- //internal bool shadow;\r
- internal bool ink;\r
-\r
- [Category("Detail")] public int Spec { get { return spec; } set { spec= value; } }\r
- //[Category("Detail")] public int Effect { get { return name; } set { name= value; } }\r
-\r
- public override string ToString()\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- sb.Append("Spec: ").AppendLine(spec.ToString());\r
- sb.Append("NumBones: ").AppendLine(numbones.ToString());\r
- sb.Append("NumVertices: ").AppendLine(numvertices.ToString());\r
- return sb.ToString();\r
- }\r
- }\r
-\r
- public struct Matrix44\r
- {\r
- public static readonly Matrix44 Identity = new Matrix44(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);\r
-\r
- public float m11, m12, m13, m14;\r
- public float m21, m22, m23, m24;\r
- public float m31, m32, m33, m34;\r
- public float m41, m42, m43, m44;\r
-\r
- public float M11 { get { return m11; } set { m11= value; } }\r
- public float M12 { get { return m12; } set { m12= value; } }\r
- public float M13 { get { return m13; } set { m13= value; } }\r
- public float M14 { get { return m14; } set { m14= value; } }\r
- public float M21 { get { return m21; } set { m21= value; } }\r
- public float M22 { get { return m22; } set { m22= value; } }\r
- public float M23 { get { return m23; } set { m23= value; } }\r
- public float M24 { get { return m24; } set { m24= value; } }\r
- public float M31 { get { return m31; } set { m31= value; } }\r
- public float M32 { get { return m32; } set { m32= value; } }\r
- public float M33 { get { return m33; } set { m33= value; } }\r
- public float M34 { get { return m34; } set { m34= value; } }\r
- public float M41 { get { return m41; } set { m41= value; } }\r
- public float M42 { get { return m42; } set { m42= value; } }\r
- public float M43 { get { return m43; } set { m43= value; } }\r
- public float M44 { get { return m44; } set { m44= value; } }\r
-\r
- public Matrix44(\r
- float a11, float a12, float a13, float a14,\r
- float a21, float a22, float a23, float a24,\r
- float a31, float a32, float a33, float a34,\r
- float a41, float a42, float a43, float a44)\r
- {\r
- m11=a11; m12=a12; m13=a13; m14=a14;\r
- m21=a21; m22=a22; m23=a23; m24=a24;\r
- m31=a31; m32=a32; m33=a33; m34=a34;\r
- m41=a41; m42=a42; m43=a43; m44=a44;\r
- }\r
-\r
- public Point3 Translation { get { return new Point3(M41, M42, M43); } } \r
-\r
- public override string ToString()\r
- {\r
- StringBuilder sb = new StringBuilder();\r
- sb.Append("[").Append(M11).Append(", ")\r
- .Append(M12).Append(", ")\r
- .Append(M13).Append(", ")\r
- .Append(M14).Append("], ")\r
- .Append("[").Append(M21).Append(", ")\r
- .Append(M22).Append(", ")\r
- .Append(M23).Append(", ")\r
- .Append(M24).Append("], ")\r
- .Append("[").Append(M31).Append(", ")\r
- .Append(M32).Append(", ")\r
- .Append(M33).Append(", ")\r
- .Append(M34).Append("], ")\r
- .Append("[").Append(M41).Append(", ")\r
- .Append(M42).Append(", ")\r
- .Append(M43).Append(", ")\r
- .Append(M44).Append("]");\r
- return sb.ToString();\r
- }\r
-\r
- public static Matrix44 Mul(Matrix44 a, Matrix44 b)\r
- {\r
- Matrix44 m = new Matrix44();\r
-\r
- m.M11 = a.M11*b.M11 + a.M12*b.M21 + a.M13*b.M31 + a.M14*b.M41;\r
- m.M12 = a.M11*b.M12 + a.M12*b.M22 + a.M13*b.M32 + a.M14*b.M42;\r
- m.M13 = a.M11*b.M13 + a.M12*b.M23 + a.M13*b.M33 + a.M14*b.M43;\r
- m.M14 = a.M11*b.M14 + a.M12*b.M24 + a.M13*b.M34 + a.M14*b.M44;\r
-\r
- m.M21 = a.M21*b.M11 + a.M22*b.M21 + a.M23*b.M31 + a.M24*b.M41;\r
- m.M22 = a.M21*b.M12 + a.M22*b.M22 + a.M23*b.M32 + a.M24*b.M42;\r
- m.M23 = a.M21*b.M13 + a.M22*b.M23 + a.M23*b.M33 + a.M24*b.M43;\r
- m.M24 = a.M21*b.M14 + a.M22*b.M24 + a.M23*b.M34 + a.M24*b.M44;\r
-\r
- m.M31 = a.M31*b.M11 + a.M32*b.M21 + a.M33*b.M31 + a.M34*b.M41;\r
- m.M32 = a.M31*b.M12 + a.M32*b.M22 + a.M33*b.M32 + a.M34*b.M42;\r
- m.M33 = a.M31*b.M13 + a.M32*b.M23 + a.M33*b.M33 + a.M34*b.M43;\r
- m.M34 = a.M31*b.M14 + a.M32*b.M24 + a.M33*b.M34 + a.M34*b.M44;\r
-\r
- m.M41 = a.M41*b.M11 + a.M42*b.M21 + a.M43*b.M31 + a.M44*b.M41;\r
- m.M42 = a.M41*b.M12 + a.M42*b.M22 + a.M43*b.M32 + a.M44*b.M42;\r
- m.M43 = a.M41*b.M13 + a.M42*b.M23 + a.M43*b.M33 + a.M44*b.M43;\r
- m.M44 = a.M41*b.M14 + a.M42*b.M24 + a.M43*b.M34 + a.M44*b.M44;\r
-\r
- return m;\r
- }\r
- }\r
-\r
- public partial struct Vertex : IComparable<Vertex>\r
- {\r
- public Vector3 Pos;\r
- public Point4 Wgt;\r
- public UInt32 Idx;\r
- public Vector3 Nrm;\r
- public Vector2 Tex;\r
- //public int Count;\r
- //public Weights[] Weights;\r
-\r
- public Vertex(Vector3 pos, Point4 wgt, UInt32 idx, Vector3 nrm, Vector2 tex)\r
- {\r
- Pos = pos;\r
- Wgt = wgt;\r
- Idx = idx;\r
- Nrm = nrm;\r
- Tex = tex;\r
- }\r
-\r
- public int CompareTo(Vertex o)\r
- {\r
- if(Pos.X < o.Pos.X) return -1; if(Pos.X > o.Pos.X) return 1;\r
- if(Pos.Y < o.Pos.Y) return -1; if(Pos.Y > o.Pos.Y) return 1;\r
- if(Pos.Z < o.Pos.Z) return -1; if(Pos.Z > o.Pos.Z) return 1;\r
- if(Nrm.X < o.Nrm.X) return -1; if(Nrm.X > o.Nrm.X) return 1;\r
- if(Nrm.Y < o.Nrm.Y) return -1; if(Nrm.Y > o.Nrm.Y) return 1;\r
- if(Nrm.Z < o.Nrm.Z) return -1; if(Nrm.Z > o.Nrm.Z) return 1;\r
- if(Tex.X < o.Tex.X) return -1; if(Tex.X > o.Tex.X) return 1;\r
- if(Tex.Y < o.Tex.Y) return -1; if(Tex.Y > o.Tex.Y) return 1;\r
- if(Wgt.x < o.Wgt.x) return -1; if(Wgt.x > o.Wgt.x) return 1;\r
- if(Wgt.y < o.Wgt.y) return -1; if(Wgt.y > o.Wgt.y) return 1;\r
- if(Wgt.z < o.Wgt.z) return -1; if(Wgt.z > o.Wgt.z) return 1;\r
- if(Wgt.w < o.Wgt.w) return -1; if(Wgt.w > o.Wgt.w) return 1;\r
- if(Idx < o.Idx) return -1; if(Idx > o.Idx) return 1;\r
- return 0;\r
- }\r
-\r
- public override int GetHashCode()\r
- {\r
- return Pos.X.GetHashCode() ^ Pos.Y.GetHashCode() ^ Pos.Z.GetHashCode()\r
- ^ Nrm.X.GetHashCode() ^ Nrm.Y.GetHashCode() ^ Nrm.Z.GetHashCode()\r
- ^ Tex.X.GetHashCode() ^ Tex.Y.GetHashCode() ^ Wgt.w.GetHashCode()\r
- ^ Wgt.x.GetHashCode() ^ Wgt.y.GetHashCode() ^ Wgt.z.GetHashCode()\r
- - Idx.GetHashCode();\r
- }\r
-\r
- public override bool Equals(object obj)\r
- {\r
- Vertex o = (Vertex)obj;\r
-\r
- return Pos.X==o.Pos.X && Pos.Y==o.Pos.Y && Pos.Z==o.Pos.Z\r
- && Nrm.X==o.Nrm.X && Nrm.Y==o.Nrm.Y && Nrm.Z==o.Nrm.Z\r
- && Tex.X==o.Tex.X && Tex.Y==o.Tex.Y && Wgt.w==o.Wgt.w\r
- && Wgt.x==o.Wgt.x && Wgt.y==o.Wgt.y && Wgt.z==o.Wgt.z\r
- && Idx ==o.Idx;\r
- }\r
- }\r
-\r
- /*\r
- public struct Weights\r
- {\r
- public int Index;\r
- public float Weight;\r
- }\r
- */\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.ComponentModel;
+
+namespace Tso2MqoGui
+{
+ public class TSOFile : TDCGFile
+ {
+ internal Dictionary<string, TSONode> nodemap;
+ internal Dictionary<string, TSOTex> texturemap;
+ internal TSONode[] nodes;
+ internal TSOTex[] textures;
+ internal TSOEffect[] effects;
+ internal TSOMaterial[] materials;
+ internal TSOMesh[] meshes;
+
+ public TSOFile(string file) : base(file) { }
+ public TSOFile(Stream s) : base(s) { }
+ public TSOFile(BinaryReader r) : base(r) { }
+
+ public void SaveTo(string file)
+ {
+ }
+
+ [System.Diagnostics.Conditional("DEBUG_DETAIL")]
+ public static void WriteLine(string s)
+ {
+ System.Diagnostics.Debug.WriteLine(s);
+ }
+
+ public static void ExchangeChannel(byte[] data, int depth)
+ {
+ for (int j = 0; j < data.Length; j += depth)
+ {
+ byte tmp = data[j + 2];
+ data[j + 2] = data[j + 0];
+ data[j + 0] = tmp;
+ }
+ }
+
+ public void ReadAll()
+ {
+ byte[] magic = r.ReadBytes(4);
+
+ if (magic[0] != (byte)'T'
+ || magic[1] != (byte)'S'
+ || magic[2] != (byte)'O'
+ || magic[3] != (byte)'1')
+ throw new Exception("File is not TSO");
+
+ //----- ノード -------------------------------------------------
+ nodemap = new Dictionary<string, TSONode>();
+ int count = r.ReadInt32();
+ nodes = new TSONode[count];
+
+ for (int i = 0; i < count; ++i)
+ {
+ nodes[i] = new TSONode();
+ nodes[i].id = i;
+ nodes[i].path = ReadString();
+ nodes[i].name = nodes[i].path.Substring(nodes[i].path.LastIndexOf('|') + 1);
+ nodemap.Add(nodes[i].path, nodes[i]);
+
+ WriteLine(i + ": " + nodes[i].path);
+ }
+
+ for (int i = 0; i < count; ++i)
+ {
+ int index = nodes[i].path.LastIndexOf('|');
+
+ if (index <= 0)
+ continue;
+
+ string pname = nodes[i].path.Substring(0, index);
+ WriteLine(pname);
+ nodes[i].parent = nodemap[pname];
+ nodes[i].parent.children.Add(nodes[i]);
+ }
+
+ WriteLine(r.BaseStream.Position.ToString("X"));
+
+ count = r.ReadInt32();
+
+ // Node Matrix
+ for (int i = 0; i < count; ++i)
+ {
+ nodes[i].matrix = ReadMatrix();
+ }
+
+ WriteLine(r.BaseStream.Position.ToString("X"));
+
+ //----- テクスチャ ---------------------------------------------
+ count = r.ReadInt32();
+ textures = new TSOTex[count];
+ texturemap = new Dictionary<string, TSOTex>();
+
+ for (int i = 0; i < count; ++i)
+ {
+ textures[i] = new TSOTex();
+ textures[i].id = i;
+ textures[i].name = ReadString();
+ textures[i].File = ReadString();
+ textures[i].width = r.ReadInt32();
+ textures[i].height = r.ReadInt32();
+ textures[i].depth = r.ReadInt32();
+ textures[i].data = r.ReadBytes(textures[i].width * textures[i].height * textures[i].depth);
+ texturemap.Add(textures[i].name, textures[i]);
+
+ ExchangeChannel(textures[i].data, textures[i].depth);
+
+ WriteLine(r.BaseStream.Position.ToString("X"));
+ }
+
+ //----- エフェクト ---------------------------------------------
+ count = r.ReadInt32();
+ effects = new TSOEffect[count];
+
+ for (int i = 0; i < count; ++i)
+ {
+ StringBuilder sb = new StringBuilder();
+ effects[i] = new TSOEffect();
+ effects[i].name = ReadString();
+ effects[i].line = r.ReadInt32();
+
+ for (int j = 0; j < effects[i].line; ++j)
+ sb.Append(ReadString()).Append('\n');
+
+ effects[i].code = sb.ToString();
+
+ WriteLine(r.BaseStream.Position.ToString("X"));
+ }
+
+ //----- マテリアル ---------------------------------------------
+ count = r.ReadInt32();
+ materials = new TSOMaterial[count];
+
+ for (int i = 0; i < count; ++i)
+ {
+ StringBuilder sb = new StringBuilder();
+ materials[i] = new TSOMaterial();
+ materials[i].id = i;
+ materials[i].name = ReadString();
+ materials[i].file = ReadString();
+ materials[i].line = r.ReadInt32();
+
+ for (int j = 0; j < materials[i].line; ++j)
+ sb.Append(ReadString()).Append('\n');
+
+ materials[i].code = sb.ToString();
+ materials[i].ParseParameters();
+
+ WriteLine(r.BaseStream.Position.ToString("X"));
+ }
+
+ //----- メッシュ -----------------------------------------------
+ count = r.ReadInt32();
+ meshes = new TSOMesh[count];
+ int check = 0;
+ for (int i = 0; i < count; ++i)
+ {
+ meshes[i] = new TSOMesh();
+ meshes[i].file = this;
+ meshes[i].name = ReadString();
+ meshes[i].matrix = ReadMatrix();
+ meshes[i].effect = r.ReadInt32();
+ meshes[i].numsubs = r.ReadInt32();
+ meshes[i].sub_meshes = new TSOSubMesh[meshes[i].numsubs];
+
+ for (int j = 0; j < meshes[i].numsubs; ++j)
+ {
+ meshes[i].sub_meshes[j] = new TSOSubMesh();
+ meshes[i].sub_meshes[j].owner = meshes[i];
+ meshes[i].sub_meshes[j].spec = r.ReadInt32();
+ meshes[i].sub_meshes[j].numbones = r.ReadInt32();
+ meshes[i].sub_meshes[j].bones = new int[meshes[i].sub_meshes[j].numbones];
+
+ for (int k = 0; k < meshes[i].sub_meshes[j].numbones; ++k)
+ meshes[i].sub_meshes[j].bones[k] = r.ReadInt32();
+
+ meshes[i].sub_meshes[j].numvertices = r.ReadInt32();
+ Vertex[] v = new Vertex[meshes[i].sub_meshes[j].numvertices];
+ meshes[i].sub_meshes[j].vertices = v;
+
+ for (int k = 0; k < meshes[i].sub_meshes[j].numvertices; ++k)
+ {
+ ReadVertex(ref v[k]);
+ }
+
+ WriteLine(r.BaseStream.Position.ToString("X"));
+ System.Diagnostics.Debug.WriteLine(r.BaseStream.Position.ToString("X"));
+ }
+ }
+
+ WriteLine(r.BaseStream.Position.ToString("X"));
+ WriteLine(check.ToString("X"));
+
+ r.BaseStream.Dispose();
+ }
+
+ // ボーンをグローバルな番号に変換
+ public unsafe void SwitchBoneIndicesOnMesh()
+ {
+ foreach (TSOMesh mesh in this.meshes)
+ foreach (TSOSubMesh sub in mesh.sub_meshes)
+ {
+ int[] bones = sub.bones;
+
+ for (int k = 0, n = sub.numvertices; k < n; ++k)
+ {
+ uint idx0 = sub.vertices[k].Idx;
+ byte* idx = (byte*)(&idx0);
+ idx[0] = (byte)bones[idx[0]];
+ idx[1] = (byte)bones[idx[1]];
+ idx[2] = (byte)bones[idx[2]];
+ idx[3] = (byte)bones[idx[3]];
+ sub.vertices[k].Idx = idx0;
+ }
+ }
+ }
+
+ public void UpdateNodesWorld()
+ {
+ foreach (TSONode node in this.nodes)
+ {
+ if (node.parent == null)
+ node.world = node.Matrix;
+ else
+ node.world = Matrix44.Mul(node.matrix, node.parent.world);
+ }
+ }
+ }
+
+ public class TSONode
+ {
+ internal int id;
+ internal string path;
+ internal string name;
+ internal Matrix44 matrix;
+ internal Matrix44 world;
+ internal List<TSONode> children = new List<TSONode>();
+ internal TSONode parent;
+
+ [Category("General")]
+ public int ID { get { return id; } }
+ [Category("General")]
+ public string Path { get { return path; } }
+ [Category("General")]
+ public string Name { get { return name; } }
+ [Category("Detail")]
+ public Matrix44 Matrix { get { return matrix; } set { matrix = value; } }
+ [Category("Detail")]
+ public Matrix44 World { get { return world; } set { world = value; } }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("Path: ").AppendLine(path);
+ sb.Append("Matrix: ").AppendLine(matrix.ToString());
+ sb.Append("Children.Count: ").AppendLine(children.Count.ToString());
+ return sb.ToString();
+ }
+ }
+
+ public class TSOTex
+ {
+ internal int id;
+ internal string name;
+ string file;
+ internal int width;
+ internal int height;
+ internal int depth;
+ internal byte[] data;
+
+ [Category("General")]
+ public int ID { get { return id; } }
+ [Category("General")]
+ public string Name { get { return name; } }
+ [Category("Detail")]
+ public string File { get { return file; } set { file = value; } }
+ [Category("Detail")]
+ public int Width { get { return width; } }
+ [Category("Detail")]
+ public int Height { get { return height; } }
+ [Category("Detail")]
+ public int Depth { get { return depth; } }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("Name: ").AppendLine(name);
+ sb.Append("File: ").AppendLine(file);
+ sb.Append("Width: ").AppendLine(width.ToString());
+ sb.Append("Height: ").AppendLine(height.ToString());
+ sb.Append("Depth: ").AppendLine(depth.ToString());
+ sb.Append("Data.Length: ").AppendLine(data.Length.ToString());
+ return sb.ToString();
+ }
+ }
+
+ public class TSOEffect
+ {
+ internal string name;
+ internal int line;
+ internal string code;
+
+ [Category("General")]
+ public string Name { get { return name; } }
+ [Category("Detail")]
+ public string Code { get { return code; } set { code = value; } }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("Name: ").AppendLine(name);
+ sb.Append("Line: ").AppendLine(line.ToString());
+ sb.AppendLine("Code:").AppendLine(code);
+ return sb.ToString();
+ }
+ }
+
+ public class TSOParameter
+ {
+ public string Name;
+ public string Type;
+ public string Value;
+
+ public TSOParameter(string type, string name, string value)
+ {
+ Name = name;
+ Type = type;
+ Value = value;
+ }
+
+ public override string ToString()
+ {
+#if true
+ return Type + " " + Name + " = " + Value;
+#else
+ switch(Type)
+ {
+ case "string": return Type + " " + Name + " = \"" + Value + "\"";
+ case "float": return Type + " " + Name + " = [" + Value + "]";
+ case "float4": return Type + " " + Name + " = [" + Value + "]";
+ default: return Type + " " + Name + " = " + Value;
+ }
+#endif
+ }
+ }
+
+ public class TSOMaterialCode : Dictionary<string, TSOParameter>
+ {
+ public TSOMaterialCode(string code)
+ : this(code.Split('\r', '\n'))
+ {
+ }
+
+ public string GetValue(string index)
+ {
+ return this[index].Value;
+ }
+
+ public void SetValue(string index, string value)
+ {
+ TSOParameter p = this[index];
+ p.Value = value;
+ }
+
+ public TSOMaterialCode(string[] code)
+ {
+ foreach (string i in code)
+ {
+ try
+ {
+ int n1, n2;
+
+ if ((n1 = i.IndexOf(' ')) < 0) continue;
+ if ((n2 = i.IndexOf('=', n1 + 1)) < 0) continue;
+
+ TSOParameter p = new TSOParameter(
+ i.Substring(0, n1).Trim(),
+ i.Substring(n1, n2 - n1).Trim(),
+ i.Substring(n2 + 1).Trim());
+ TSOFile.WriteLine(p.ToString());
+ Add(p.Name, p);
+ }
+ catch (Exception e)
+ {
+ System.Diagnostics.Debug.WriteLine(e);
+ }
+ }
+ }
+
+ public static TSOMaterialCode GenerateFromFile(string filename)
+ {
+ return new TSOMaterialCode(File.ReadAllLines(filename));
+ }
+ }
+
+ public class TSOMaterial
+ {
+ internal int id;
+ internal string name;
+ internal string file;
+ internal int line;
+ internal string code;
+ internal TSOMaterialCode codedata;
+
+ internal string description; // = "TA ToonShader v0.50"
+ internal string shader; // = "TAToonshade_050.cgfx"
+ internal string technique; // = "ShadowOn"
+ internal float lightDirX; // = [-0.00155681]
+ internal float lightDirY; // = [-0.0582338]
+ internal float lightDirZ; // = [-0.998302]
+ internal float lightDirW; // = [0]
+ internal Point4 shadowColor; // = [0, 0, 0, 1]
+ internal string shadeTex; // = Ninjya_Ribbon_Toon_Tex
+ internal float highLight; // = [0]
+ internal float colorBlend; // = [10]
+ internal float highLightBlend; // = [10]
+ internal Point4 penColor; // = [0.166, 0.166, 0.166, 1]
+ internal float ambient; // = [38]
+ internal string colorTex; // = file24
+ internal float thickness; // = [0.018]
+ internal float shadeBlend; // = [10]
+ internal float highLightPower; // = [100]
+
+ [Category("General")]
+ public int ID { get { return id; } }
+ [Category("General")]
+ public string Name { get { return name; } }
+ [Category("Detail")]
+ public string File { get { return file; } }
+ [Category("Detail")]
+ public string Code { get { return code; } set { code = value; } }
+
+ [Category("Parameters")]
+ public string Description { get { return description; } set { description = value; } }
+ [Category("Parameters")]
+ public string Shader { get { return shader; } set { shader = value; } }
+ [Category("Parameters")]
+ public string Technique { get { return technique; } set { technique = value; } }
+ [Category("Parameters")]
+ public float LightDirX { get { return lightDirX; } set { lightDirX = value; } }
+ [Category("Parameters")]
+ public float LightDirY { get { return lightDirY; } set { lightDirY = value; } }
+ [Category("Parameters")]
+ public float LightDirZ { get { return lightDirZ; } set { lightDirZ = value; } }
+ [Category("Parameters")]
+ public float LightDirW { get { return lightDirW; } set { lightDirW = value; } }
+ [Category("Parameters")]
+ public Point4 ShadowColor { get { return shadowColor; } set { shadowColor = value; } }
+ [Category("Parameters")]
+ public string ShadeTex { get { return shadeTex; } set { shadeTex = value; } }
+ [Category("Parameters")]
+ public float HighLight { get { return highLight; } set { highLight = value; } }
+ [Category("Parameters")]
+ public float ColorBlend { get { return colorBlend; } set { colorBlend = value; } }
+ [Category("Parameters")]
+ public float HighLightBlend { get { return highLightBlend; } set { highLightBlend = value; } }
+ [Category("Parameters")]
+ public Point4 PenColor { get { return penColor; } set { penColor = value; } }
+ [Category("Parameters")]
+ public float Ambient { get { return ambient; } set { ambient = value; } }
+ [Category("Parameters")]
+ public string ColorTex { get { return colorTex; } set { colorTex = value; } }
+ [Category("Parameters")]
+ public float Thickness { get { return thickness; } set { thickness = value; } }
+ [Category("Parameters")]
+ public float ShadeBlend { get { return shadeBlend; } set { shadeBlend = value; } }
+ [Category("Parameters")]
+ public float HighLightPower { get { return highLightPower; } set { highLightPower = value; } }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("Name: ").AppendLine(name);
+ sb.Append("File: ").AppendLine(file);
+ sb.Append("Line: ").AppendLine(line.ToString());
+ sb.AppendLine("Code:").AppendLine(code);
+
+ return sb.ToString();
+ }
+
+ public void ParseParameters()
+ {
+ codedata = new TSOMaterialCode(code);
+
+ foreach (TSOParameter i in codedata.Values)
+ SetValue(i.Type, i.Name, i.Value);
+ }
+
+ public void SetValue(string type, string name, string value)
+ {
+ switch (name)
+ {
+ case "description": description = GetString(value); break; // = "TA ToonShader v0.50"
+ case "shader": shader = GetString(value); break; // = "TAToonshade_050.cgfx"
+ case "technique": technique = GetString(value); break; // = "ShadowOn"
+ case "LightDirX": lightDirX = GetFloat(value); break; // = [-0.00155681]
+ case "LightDirY": lightDirY = GetFloat(value); break; // = [-0.0582338]
+ case "LightDirZ": lightDirZ = GetFloat(value); break; // = [-0.998302]
+ case "LightDirW": lightDirW = GetFloat(value); break; // = [0]
+ case "ShadowColor": shadowColor = GetPoint4(value); break; // = [0, 0, 0, 1]
+ case "ShadeTex": shadeTex = GetTexture(value); break; // = Ninjya_Ribbon_Toon_Tex
+ case "HighLight": highLight = GetFloat(value); break; // = [0]
+ case "ColorBlend": colorBlend = GetFloat(value); break; // = [10]
+ case "HighLightBlend": highLightBlend = GetFloat(value); break; // = [10]
+ case "PenColor": penColor = GetPoint4(value); break; // = [0.166, 0.166, 0.166, 1]
+ case "Ambient": ambient = GetFloat(value); break; // = [38]
+ case "ColorTex": colorTex = GetTexture(value); break; // = file24
+ case "Thickness": thickness = GetFloat(value); break; // = [0.018]
+ case "ShadeBlend": shadeBlend = GetFloat(value); break; // = [10]
+ case "HighLightPower": highLightPower = GetFloat(value); break; // = [100]
+ default:
+ TSOFile.WriteLine("Unknown parameter. type=" + type + ", name=" + name + ", value=" + value);
+ break;
+ }
+ }
+
+ public string GetTexture(string value)
+ {
+ return value;
+ }
+
+ public string GetString(string value)
+ {
+ return value.Trim('"');
+ }
+
+ public float GetFloat(string value)
+ {
+ return float.Parse(value.Trim('[', ']', ' '));
+ }
+
+ public Point4 GetPoint4(string value)
+ {
+ string[] token = value.Trim('[', ']', ' ').Split(',');
+ Point4 p = new Point4();
+ p.X = float.Parse(token[0].Trim());
+ p.Y = float.Parse(token[1].Trim());
+ p.Z = float.Parse(token[2].Trim());
+ p.W = float.Parse(token[3].Trim());
+ return p;
+ }
+ }
+
+ public class TSOMesh
+ {
+ internal TSOFile file;
+ internal string name;
+ internal Matrix44 matrix;
+ internal int effect;
+ internal int numsubs;
+ internal TSOSubMesh[] sub_meshes;
+
+ [Category("General")]
+ public string Name { get { return name; } set { name = value; } }
+ //[Category("Detail")] public int Effect { get { return name; } set { name= value; } }
+ [Category("Detail")]
+ public Matrix44 Matrix { get { return matrix; } set { matrix = value; } }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("Name: ").AppendLine(name);
+ sb.Append("Matrix: ").AppendLine(matrix.ToString());
+ sb.Append("Effect?: ").AppendLine(effect.ToString());
+ sb.Append("NumSubs: ").AppendLine(numsubs.ToString());
+ sb.Append("SubMesh.Count: ").AppendLine(sub_meshes.Length.ToString());
+ return sb.ToString();
+ }
+ }
+
+ public class TSOSubMesh
+ {
+ internal int spec;
+ internal int numbones;
+ internal int[] bones;
+ internal int numvertices;
+ internal Vertex[] vertices;
+ internal TSOMesh owner;
+
+ [Category("Detail")]
+ public int Spec { get { return spec; } set { spec = value; } }
+ //[Category("Detail")] public int Effect { get { return name; } set { name= value; } }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("Spec: ").AppendLine(spec.ToString());
+ sb.Append("NumBones: ").AppendLine(numbones.ToString());
+ sb.Append("NumVertices: ").AppendLine(numvertices.ToString());
+ return sb.ToString();
+ }
+ }
+
+ public struct Matrix44
+ {
+ public static readonly Matrix44 Identity = new Matrix44(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+
+ public float m11, m12, m13, m14;
+ public float m21, m22, m23, m24;
+ public float m31, m32, m33, m34;
+ public float m41, m42, m43, m44;
+
+ public float M11 { get { return m11; } set { m11 = value; } }
+ public float M12 { get { return m12; } set { m12 = value; } }
+ public float M13 { get { return m13; } set { m13 = value; } }
+ public float M14 { get { return m14; } set { m14 = value; } }
+ public float M21 { get { return m21; } set { m21 = value; } }
+ public float M22 { get { return m22; } set { m22 = value; } }
+ public float M23 { get { return m23; } set { m23 = value; } }
+ public float M24 { get { return m24; } set { m24 = value; } }
+ public float M31 { get { return m31; } set { m31 = value; } }
+ public float M32 { get { return m32; } set { m32 = value; } }
+ public float M33 { get { return m33; } set { m33 = value; } }
+ public float M34 { get { return m34; } set { m34 = value; } }
+ public float M41 { get { return m41; } set { m41 = value; } }
+ public float M42 { get { return m42; } set { m42 = value; } }
+ public float M43 { get { return m43; } set { m43 = value; } }
+ public float M44 { get { return m44; } set { m44 = value; } }
+
+ public Matrix44(
+ float a11, float a12, float a13, float a14,
+ float a21, float a22, float a23, float a24,
+ float a31, float a32, float a33, float a34,
+ float a41, float a42, float a43, float a44)
+ {
+ m11 = a11; m12 = a12; m13 = a13; m14 = a14;
+ m21 = a21; m22 = a22; m23 = a23; m24 = a24;
+ m31 = a31; m32 = a32; m33 = a33; m34 = a34;
+ m41 = a41; m42 = a42; m43 = a43; m44 = a44;
+ }
+
+ public Point3 Translation { get { return new Point3(M41, M42, M43); } }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}], ", M11, M12, M13, M14)
+ .AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}], ", M21, M22, M23, M24)
+ .AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}], ", M31, M32, M33, M34)
+ .AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}]", M41, M42, M43, M44);
+ return sb.ToString();
+ }
+
+ public static Matrix44 Mul(Matrix44 a, Matrix44 b)
+ {
+ Matrix44 m = new Matrix44();
+
+ m.M11 = a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31 + a.M14 * b.M41;
+ m.M12 = a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32 + a.M14 * b.M42;
+ m.M13 = a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33 + a.M14 * b.M43;
+ m.M14 = a.M11 * b.M14 + a.M12 * b.M24 + a.M13 * b.M34 + a.M14 * b.M44;
+
+ m.M21 = a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31 + a.M24 * b.M41;
+ m.M22 = a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32 + a.M24 * b.M42;
+ m.M23 = a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33 + a.M24 * b.M43;
+ m.M24 = a.M21 * b.M14 + a.M22 * b.M24 + a.M23 * b.M34 + a.M24 * b.M44;
+
+ m.M31 = a.M31 * b.M11 + a.M32 * b.M21 + a.M33 * b.M31 + a.M34 * b.M41;
+ m.M32 = a.M31 * b.M12 + a.M32 * b.M22 + a.M33 * b.M32 + a.M34 * b.M42;
+ m.M33 = a.M31 * b.M13 + a.M32 * b.M23 + a.M33 * b.M33 + a.M34 * b.M43;
+ m.M34 = a.M31 * b.M14 + a.M32 * b.M24 + a.M33 * b.M34 + a.M34 * b.M44;
+
+ m.M41 = a.M41 * b.M11 + a.M42 * b.M21 + a.M43 * b.M31 + a.M44 * b.M41;
+ m.M42 = a.M41 * b.M12 + a.M42 * b.M22 + a.M43 * b.M32 + a.M44 * b.M42;
+ m.M43 = a.M41 * b.M13 + a.M42 * b.M23 + a.M43 * b.M33 + a.M44 * b.M43;
+ m.M44 = a.M41 * b.M14 + a.M42 * b.M24 + a.M43 * b.M34 + a.M44 * b.M44;
+
+ return m;
+ }
+ }
+
+ public partial struct Vertex : IComparable<Vertex>
+ {
+ public Point3 Pos;
+ public Point4 Wgt;
+ public UInt32 Idx;
+ public Point3 Nrm;
+ public Point2 Tex;
+
+ public Vertex(Point3 pos, Point4 wgt, UInt32 idx, Point3 nrm, Point2 tex)
+ {
+ Pos = pos;
+ Wgt = wgt;
+ Idx = idx;
+ Nrm = nrm;
+ Tex = tex;
+ }
+
+ public int CompareTo(Vertex o)
+ {
+ int cmp = 0;
+ cmp = Pos.CompareTo(o.Pos); if (cmp != 0) return cmp;
+ cmp = Tex.CompareTo(o.Tex);
+ return cmp;
+ }
+
+ public override int GetHashCode()
+ {
+ return Pos.GetHashCode() ^ Tex.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vertex)
+ {
+ Vertex v = (Vertex)obj;
+ return Pos.Equals(v.Pos) && Tex.Equals(v.Tex);
+ }
+ return false;
+ }
+
+ public bool Equals(Vertex v)
+ {
+ return Pos.Equals(v.Pos) && Tex.Equals(v.Tex);
+ }
+ }
+}