OSDN Git Service

rename TSONode#name to path.
[tdcgexplorer/tso2mqo.git] / TSOFile.cs
index 415d6f5..0937ced 100644 (file)
-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);
+        }
+    }
+}