2 using System.Collections.Generic;
\r
5 using System.ComponentModel;
\r
9 public class TSOFile : TDCGFile
\r
11 internal Dictionary<string, TSONode> nodemap;
\r
12 internal Dictionary<string, TSOTex> texturemap;
\r
13 internal TSONode[] nodes;
\r
14 internal TSOTex[] textures;
\r
15 internal TSOEffect[] effects;
\r
16 internal TSOMaterial[] materials;
\r
17 internal TSOMesh[] meshes;
\r
19 public TSOFile(string file) : base(file) {}
\r
20 public TSOFile(Stream s) : base(s) {}
\r
21 public TSOFile(BinaryReader r) : base(r) {}
\r
23 public void SaveTo(string file)
\r
27 [System.Diagnostics.Conditional("DEBUG_DETAIL")]
\r
28 public static void WriteLine(string s)
\r
30 System.Diagnostics.Debug.WriteLine(s);
\r
33 public static void ExchangeChannel(byte[] data, int depth)
\r
35 for(int j= 0; j < data.Length; j+=depth)
\r
37 byte tmp = data[j+2];
\r
38 data[j+2] = data[j+0];
\r
43 public void ReadAll()
\r
45 byte[] magic = r.ReadBytes(4);
\r
47 if(magic[0] != (byte)'T'
\r
48 || magic[1] != (byte)'S'
\r
49 || magic[2] != (byte)'O'
\r
50 || magic[3] != (byte)'1')
\r
51 throw new Exception("File is not TSO");
\r
53 //----- ノード -------------------------------------------------
\r
54 nodemap = new Dictionary<string, TSONode>();
\r
55 int count = r.ReadInt32();
\r
56 nodes = new TSONode[count];
\r
58 for(int i= 0; i < count; ++i)
\r
60 nodes[i] = new TSONode();
\r
62 nodes[i].name = ReadString();
\r
63 nodes[i].sname = nodes[i].name.Substring(nodes[i].name.LastIndexOf('|')+1);
\r
64 nodemap.Add(nodes[i].name, nodes[i]);
\r
66 WriteLine(i+ ": " + nodes[i].name);
\r
69 for(int i= 0; i < count; ++i)
\r
71 int index = nodes[i].name.LastIndexOf('|');
\r
76 string pname = nodes[i].name.Substring(0, index);
\r
78 nodes[i].parent = nodemap[pname];
\r
79 nodes[i].parent.children.Add(nodes[i]);
\r
82 WriteLine(r.BaseStream.Position.ToString("X"));
\r
84 count = r.ReadInt32();
\r
87 for(int i= 0; i < count; ++i)
\r
89 nodes[i].matrix = ReadMatrix();
\r
92 WriteLine(r.BaseStream.Position.ToString("X"));
\r
94 //----- テクスチャ ---------------------------------------------
\r
95 count = r.ReadInt32();
\r
96 textures = new TSOTex[count];
\r
97 texturemap = new Dictionary<string, TSOTex>();
\r
99 for(int i= 0; i < count; ++i)
\r
101 textures[i] = new TSOTex();
\r
102 textures[i].id = i;
\r
103 textures[i].name = ReadString();
\r
104 textures[i].file = ReadString();
\r
105 textures[i].width = r.ReadInt32();
\r
106 textures[i].height = r.ReadInt32();
\r
107 textures[i].depth = r.ReadInt32();
\r
108 textures[i].data = r.ReadBytes(textures[i].width * textures[i].height * textures[i].depth);
\r
109 texturemap.Add(textures[i].name, textures[i]);
\r
111 ExchangeChannel(textures[i].data, textures[i].depth);
\r
113 WriteLine(r.BaseStream.Position.ToString("X"));
\r
116 //----- エフェクト ---------------------------------------------
\r
117 count = r.ReadInt32();
\r
118 effects = new TSOEffect[count];
\r
120 for(int i= 0; i < count; ++i)
\r
122 StringBuilder sb = new StringBuilder();
\r
123 effects[i] = new TSOEffect();
\r
124 effects[i].name = ReadString();
\r
125 effects[i].line = r.ReadInt32();
\r
127 for(int j= 0; j < effects[i].line; ++j)
\r
128 sb.Append(ReadString()).Append('\n');
\r
130 effects[i].code = sb.ToString();
\r
132 WriteLine(r.BaseStream.Position.ToString("X"));
\r
135 //----- マテリアル ---------------------------------------------
\r
136 count = r.ReadInt32();
\r
137 materials = new TSOMaterial[count];
\r
139 for(int i= 0; i < count; ++i)
\r
141 StringBuilder sb = new StringBuilder();
\r
142 materials[i] = new TSOMaterial();
\r
143 materials[i].id = i;
\r
144 materials[i].name = ReadString();
\r
145 materials[i].file = ReadString();
\r
146 materials[i].line = r.ReadInt32();
\r
148 for(int j= 0; j < materials[i].line; ++j)
\r
149 sb.Append(ReadString()).Append('\n');
\r
151 materials[i].code = sb.ToString();
\r
152 materials[i].ParseParameters();
\r
154 WriteLine(r.BaseStream.Position.ToString("X"));
\r
157 //----- メッシュ -----------------------------------------------
\r
158 count = r.ReadInt32();
\r
159 meshes = new TSOMesh[count];
\r
161 for(int i= 0; i < count; ++i)
\r
163 meshes[i] = new TSOMesh();
\r
164 meshes[i].file = this;
\r
165 meshes[i].name = ReadString();
\r
166 meshes[i].matrix = ReadMatrix();
\r
167 meshes[i].effect = r.ReadInt32();
\r
168 meshes[i].numsubs = r.ReadInt32();
\r
169 meshes[i].sub = new TSOSubMesh[meshes[i].numsubs];
\r
171 for(int j= 0; j < meshes[i].numsubs; ++j)
\r
173 meshes[i].sub[j] = new TSOSubMesh();
\r
174 meshes[i].sub[j].owner = meshes[i];
\r
175 meshes[i].sub[j].spec = r.ReadInt32();
\r
176 meshes[i].sub[j].numbones = r.ReadInt32();
\r
177 meshes[i].sub[j].bones = new int[meshes[i].sub[j].numbones];
\r
179 meshes[i].sub[j].ink = materials[meshes[i].sub[j].spec].technique.ToUpper().IndexOf("INKOFF") < 0;
\r
180 //meshes[i].sub[j].shadow = specs[meshes[i].sub[j].spec].technique.ToUpper().IndexOf(Shadow
\r
182 for(int k= 0; k < meshes[i].sub[j].numbones; ++k)
\r
183 meshes[i].sub[j].bones[k] = r.ReadInt32();
\r
185 meshes[i].sub[j].numvertices= r.ReadInt32();
\r
186 Vertex[] v = new Vertex[meshes[i].sub[j].numvertices];
\r
187 meshes[i].sub[j].vertices= v;
\r
189 for(int k= 0; k < meshes[i].sub[j].numvertices; ++k)
\r
191 ReadVertex(ref v[k]);
\r
194 WriteLine(r.BaseStream.Position.ToString("X"));
\r
195 System.Diagnostics.Debug.WriteLine(r.BaseStream.Position.ToString("X"));
\r
199 WriteLine(r.BaseStream.Position.ToString("X"));
\r
200 WriteLine(check.ToString("X"));
\r
202 r.BaseStream.Dispose();
\r
206 public class TSONode
\r
209 internal string name;
\r
210 internal string sname;
\r
211 internal Matrix44 matrix;
\r
212 internal Matrix44 world;
\r
213 internal List<TSONode> children = new List<TSONode>();
\r
214 internal TSONode parent;
\r
216 [Category("General")] public int ID { get { return id; } }
\r
217 [Category("General")] public string Name { get { return name; } }
\r
218 [Category("General")] public string ShortName { get { return sname; } }
\r
219 [Category("Detail")] public Matrix44 Matrix { get { return matrix; } set { matrix= value; } }
\r
220 [Category("Detail")] public Matrix44 World { get { return world; } set { world = value; } }
\r
222 public override string ToString()
\r
224 StringBuilder sb = new StringBuilder();
\r
225 sb.Append("Name: ").AppendLine(name);
\r
226 sb.Append("Matrix: ").AppendLine(matrix.ToString());
\r
227 sb.Append("Children.Count: ").AppendLine(children.Count.ToString());
\r
228 return sb.ToString();
\r
232 public class TSOTex
\r
235 internal string name;
\r
236 internal string file;
\r
237 internal int width;
\r
238 internal int height;
\r
239 internal int depth;
\r
240 internal byte[] data;
\r
242 [Category("General")] public int ID { get { return id; } }
\r
243 [Category("General")] public string Name { get { return name; } }
\r
244 [Category("Detail")] public string File { get { return file; } set { file= value; } }
\r
245 [Category("Detail")] public int Width { get { return width; } }
\r
246 [Category("Detail")] public int Height { get { return height; } }
\r
247 [Category("Detail")] public int Depth { get { return depth; } }
\r
249 public override string ToString()
\r
251 StringBuilder sb = new StringBuilder();
\r
252 sb.Append("Name: ").AppendLine(name);
\r
253 sb.Append("File: ").AppendLine(file);
\r
254 sb.Append("Width: ").AppendLine(width.ToString());
\r
255 sb.Append("Height: ").AppendLine(height.ToString());
\r
256 sb.Append("Depth: ").AppendLine(depth.ToString());
\r
257 sb.Append("Data.Length: ").AppendLine(data.Length.ToString());
\r
258 return sb.ToString();
\r
262 public class TSOEffect
\r
264 internal string name;
\r
266 internal string code;
\r
268 [Category("General")] public string Name { get { return name; } }
\r
269 [Category("Detail")] public string Code { get { return code; } set { code= value; } }
\r
271 public override string ToString()
\r
273 StringBuilder sb = new StringBuilder();
\r
274 sb.Append("Name: ").AppendLine(name);
\r
275 sb.Append("Line: ").AppendLine(line.ToString());
\r
276 sb.AppendLine("Code:").AppendLine(code);
\r
277 return sb.ToString();
\r
281 public class TSOParameter
\r
283 public string Name;
\r
284 public string Type;
\r
285 public string Value;
\r
287 public TSOParameter(string type, string name, string value)
\r
294 public override string ToString()
\r
297 return Type + " " + Name + " = " + Value;
\r
301 case "string": return Type + " " + Name + " = \"" + Value + "\"";
\r
302 case "float": return Type + " " + Name + " = [" + Value + "]";
\r
303 case "float4": return Type + " " + Name + " = [" + Value + "]";
\r
304 default: return Type + " " + Name + " = " + Value;
\r
310 public class TSOMaterialCode : Dictionary<string, TSOParameter>
\r
312 public TSOMaterialCode(string code)
\r
313 : this(code.Split('\r', '\n'))
\r
317 public string GetValue(string index)
\r
319 return this[index].Value;
\r
322 public void SetValue(string index, string value)
\r
324 TSOParameter p = this[index];
\r
328 public TSOMaterialCode(string[] code)
\r
330 foreach(string i in code)
\r
336 if((n1= i.IndexOf(' ')) < 0) continue;
\r
337 if((n2= i.IndexOf('=', n1+1)) < 0) continue;
\r
339 TSOParameter p = new TSOParameter(
\r
340 i.Substring(0, n1) .Trim(),
\r
341 i.Substring(n1, n2-n1).Trim(),
\r
342 i.Substring(n2+1) .Trim());
\r
343 TSOFile.WriteLine(p.ToString());
\r
345 } catch(Exception e)
\r
347 System.Diagnostics.Debug.WriteLine(e);
\r
352 public static TSOMaterialCode GenerateFromFile(string filename)
\r
354 return new TSOMaterialCode(File.ReadAllLines(filename));
\r
358 public class TSOMaterial
\r
361 internal string name;
\r
362 internal string file;
\r
364 internal string code;
\r
365 internal TSOMaterialCode codedata;
\r
367 internal string description; // = "TA ToonShader v0.50"
\r
368 internal string shader; // = "TAToonshade_050.cgfx"
\r
369 internal string technique; // = "ShadowOn"
\r
370 internal float lightDirX; // = [-0.00155681]
\r
371 internal float lightDirY; // = [-0.0582338]
\r
372 internal float lightDirZ; // = [-0.998302]
\r
373 internal float lightDirW; // = [0]
\r
374 internal Point4 shadowColor; // = [0, 0, 0, 1]
\r
375 internal string shadeTex; // = Ninjya_Ribbon_Toon_Tex
\r
376 internal float highLight; // = [0]
\r
377 internal float colorBlend; // = [10]
\r
378 internal float highLightBlend; // = [10]
\r
379 internal Point4 penColor; // = [0.166, 0.166, 0.166, 1]
\r
380 internal float ambient; // = [38]
\r
381 internal string colorTex; // = file24
\r
382 internal float thickness; // = [0.018]
\r
383 internal float shadeBlend; // = [10]
\r
384 internal float highLightPower; // = [100]
\r
386 [Category("General")] public int ID { get { return id; } }
\r
387 [Category("General")] public string Name { get { return name; } }
\r
388 [Category("Detail")] public string File { get { return file; } }
\r
389 [Category("Detail")] public string Code { get { return code; } set { code= value; } }
\r
391 [Category("Parameters")] public string Description { get { return description; } set { description = value; } }
\r
392 [Category("Parameters")] public string Shader { get { return shader; } set { shader = value; } }
\r
393 [Category("Parameters")] public string Technique { get { return technique; } set { technique = value; } }
\r
394 [Category("Parameters")] public float LightDirX { get { return lightDirX; } set { lightDirX = value; } }
\r
395 [Category("Parameters")] public float LightDirY { get { return lightDirY; } set { lightDirY = value; } }
\r
396 [Category("Parameters")] public float LightDirZ { get { return lightDirZ; } set { lightDirZ = value; } }
\r
397 [Category("Parameters")] public float LightDirW { get { return lightDirW; } set { lightDirW = value; } }
\r
398 [Category("Parameters")] public Point4 ShadowColor { get { return shadowColor; } set { shadowColor = value; } }
\r
399 [Category("Parameters")] public string ShadeTex { get { return shadeTex; } set { shadeTex = value; } }
\r
400 [Category("Parameters")] public float HighLight { get { return highLight; } set { highLight = value; } }
\r
401 [Category("Parameters")] public float ColorBlend { get { return colorBlend; } set { colorBlend = value; } }
\r
402 [Category("Parameters")] public float HighLightBlend { get { return highLightBlend; } set { highLightBlend= value; } }
\r
403 [Category("Parameters")] public Point4 PenColor { get { return penColor; } set { penColor = value; } }
\r
404 [Category("Parameters")] public float Ambient { get { return ambient; } set { ambient = value; } }
\r
405 [Category("Parameters")] public string ColorTex { get { return colorTex; } set { colorTex = value; } }
\r
406 [Category("Parameters")] public float Thickness { get { return thickness; } set { thickness = value; } }
\r
407 [Category("Parameters")] public float ShadeBlend { get { return shadeBlend; } set { shadeBlend = value; } }
\r
408 [Category("Parameters")] public float HighLightPower { get { return highLightPower; } set { highLightPower= value; } }
\r
410 public override string ToString()
\r
412 StringBuilder sb = new StringBuilder();
\r
413 sb.Append("Name: ").AppendLine(name);
\r
414 sb.Append("File: ").AppendLine(file);
\r
415 sb.Append("Line: ").AppendLine(line.ToString());
\r
416 sb.AppendLine("Code:").AppendLine(code);
\r
418 return sb.ToString();
\r
421 public void ParseParameters()
\r
423 codedata = new TSOMaterialCode(code);
\r
425 foreach(TSOParameter i in codedata.Values)
\r
426 SetValue(i.Type, i.Name, i.Value);
\r
429 public void SetValue(string type, string name, string value)
\r
433 case "description": description = GetString (value); break; // = "TA ToonShader v0.50"
\r
434 case "shader": shader = GetString (value); break; // = "TAToonshade_050.cgfx"
\r
435 case "technique": technique = GetString (value); break; // = "ShadowOn"
\r
436 case "LightDirX": lightDirX = GetFloat (value); break; // = [-0.00155681]
\r
437 case "LightDirY": lightDirY = GetFloat (value); break; // = [-0.0582338]
\r
438 case "LightDirZ": lightDirZ = GetFloat (value); break; // = [-0.998302]
\r
439 case "LightDirW": lightDirW = GetFloat (value); break; // = [0]
\r
440 case "ShadowColor": shadowColor = GetPoint4 (value); break; // = [0, 0, 0, 1]
\r
441 case "ShadeTex": shadeTex = GetTexture(value); break; // = Ninjya_Ribbon_Toon_Tex
\r
442 case "HighLight": highLight = GetFloat (value); break; // = [0]
\r
443 case "ColorBlend": colorBlend = GetFloat (value); break; // = [10]
\r
444 case "HighLightBlend": highLightBlend = GetFloat (value); break; // = [10]
\r
445 case "PenColor": penColor = GetPoint4 (value); break; // = [0.166, 0.166, 0.166, 1]
\r
446 case "Ambient": ambient = GetFloat (value); break; // = [38]
\r
447 case "ColorTex": colorTex = GetTexture(value); break; // = file24
\r
448 case "Thickness": thickness = GetFloat (value); break; // = [0.018]
\r
449 case "ShadeBlend": shadeBlend = GetFloat (value); break; // = [10]
\r
450 case "HighLightPower": highLightPower = GetFloat (value); break; // = [100]
\r
452 TSOFile.WriteLine("Unknown parameter. type=" + type + ", name=" + name + ", value=" + value);
\r
457 public string GetTexture(string value)
\r
462 public string GetString(string value)
\r
464 return value.Trim('"');
\r
467 public float GetFloat(string value)
\r
469 return float.Parse(value.Trim('[', ']', ' '));
\r
472 public Point4 GetPoint4(string value)
\r
474 string[] token = value.Trim('[', ']', ' ').Split(',');
\r
475 Point4 p = new Point4();
\r
476 p.X = float.Parse(token[0].Trim());
\r
477 p.Y = float.Parse(token[1].Trim());
\r
478 p.Z = float.Parse(token[2].Trim());
\r
479 p.W = float.Parse(token[3].Trim());
\r
484 public class TSOMesh
\r
486 internal TSOFile file;
\r
487 internal string name;
\r
488 internal Matrix44 matrix;
\r
489 internal int effect;
\r
490 internal int numsubs;
\r
491 internal TSOSubMesh[] sub;
\r
493 [Category("General")] public string Name { get { return name; } set { name= value; } }
\r
494 //[Category("Detail")] public int Effect { get { return name; } set { name= value; } }
\r
495 [Category("Detail")] public Matrix44 Matrix { get { return matrix; } set { matrix= value; } }
\r
497 public override string ToString()
\r
499 StringBuilder sb = new StringBuilder();
\r
500 sb.Append("Name: ").AppendLine(name);
\r
501 sb.Append("Matrix: ").AppendLine(matrix.ToString());
\r
502 sb.Append("Effect?: ").AppendLine(effect.ToString());
\r
503 sb.Append("NumSubs: ").AppendLine(numsubs.ToString());
\r
504 sb.Append("SubMesh.Count: ").AppendLine(sub.Length.ToString());
\r
505 return sb.ToString();
\r
509 public class TSOSubMesh
\r
512 internal int numbones;
\r
513 internal int[] bones;
\r
514 internal int numvertices;
\r
515 internal Vertex[] vertices;
\r
516 internal TSOMesh owner;
\r
517 //internal bool shadow;
\r
520 [Category("Detail")] public int Spec { get { return spec; } set { spec= value; } }
\r
521 //[Category("Detail")] public int Effect { get { return name; } set { name= value; } }
\r
523 public override string ToString()
\r
525 StringBuilder sb = new StringBuilder();
\r
526 sb.Append("Spec: ").AppendLine(spec.ToString());
\r
527 sb.Append("NumBones: ").AppendLine(numbones.ToString());
\r
528 sb.Append("NumVertices: ").AppendLine(numvertices.ToString());
\r
529 return sb.ToString();
\r
533 public struct Matrix44
\r
535 public static readonly Matrix44 Identity = new Matrix44(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
\r
537 public float m11, m12, m13, m14;
\r
538 public float m21, m22, m23, m24;
\r
539 public float m31, m32, m33, m34;
\r
540 public float m41, m42, m43, m44;
\r
542 public float M11 { get { return m11; } set { m11= value; } }
\r
543 public float M12 { get { return m12; } set { m12= value; } }
\r
544 public float M13 { get { return m13; } set { m13= value; } }
\r
545 public float M14 { get { return m14; } set { m14= value; } }
\r
546 public float M21 { get { return m21; } set { m21= value; } }
\r
547 public float M22 { get { return m22; } set { m22= value; } }
\r
548 public float M23 { get { return m23; } set { m23= value; } }
\r
549 public float M24 { get { return m24; } set { m24= value; } }
\r
550 public float M31 { get { return m31; } set { m31= value; } }
\r
551 public float M32 { get { return m32; } set { m32= value; } }
\r
552 public float M33 { get { return m33; } set { m33= value; } }
\r
553 public float M34 { get { return m34; } set { m34= value; } }
\r
554 public float M41 { get { return m41; } set { m41= value; } }
\r
555 public float M42 { get { return m42; } set { m42= value; } }
\r
556 public float M43 { get { return m43; } set { m43= value; } }
\r
557 public float M44 { get { return m44; } set { m44= value; } }
\r
560 float a11, float a12, float a13, float a14,
\r
561 float a21, float a22, float a23, float a24,
\r
562 float a31, float a32, float a33, float a34,
\r
563 float a41, float a42, float a43, float a44)
\r
565 m11=a11; m12=a12; m13=a13; m14=a14;
\r
566 m21=a21; m22=a22; m23=a23; m24=a24;
\r
567 m31=a31; m32=a32; m33=a33; m34=a34;
\r
568 m41=a41; m42=a42; m43=a43; m44=a44;
\r
571 public Point3 Translation { get { return new Point3(M41, M42, M43); } }
\r
573 public override string ToString()
\r
575 StringBuilder sb = new StringBuilder();
\r
576 sb.AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}], ", M11, M12, M13, M14)
\r
577 .AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}], ", M21, M22, M23, M24)
\r
578 .AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}], ", M31, M32, M33, M34)
\r
579 .AppendFormat("[{0:F4}, {1:F4}, {2:F4}, {3:F4}]", M41, M42, M43, M44);
\r
580 return sb.ToString();
\r
583 public static Matrix44 Mul(Matrix44 a, Matrix44 b)
\r
585 Matrix44 m = new Matrix44();
\r
587 m.M11 = a.M11*b.M11 + a.M12*b.M21 + a.M13*b.M31 + a.M14*b.M41;
\r
588 m.M12 = a.M11*b.M12 + a.M12*b.M22 + a.M13*b.M32 + a.M14*b.M42;
\r
589 m.M13 = a.M11*b.M13 + a.M12*b.M23 + a.M13*b.M33 + a.M14*b.M43;
\r
590 m.M14 = a.M11*b.M14 + a.M12*b.M24 + a.M13*b.M34 + a.M14*b.M44;
\r
592 m.M21 = a.M21*b.M11 + a.M22*b.M21 + a.M23*b.M31 + a.M24*b.M41;
\r
593 m.M22 = a.M21*b.M12 + a.M22*b.M22 + a.M23*b.M32 + a.M24*b.M42;
\r
594 m.M23 = a.M21*b.M13 + a.M22*b.M23 + a.M23*b.M33 + a.M24*b.M43;
\r
595 m.M24 = a.M21*b.M14 + a.M22*b.M24 + a.M23*b.M34 + a.M24*b.M44;
\r
597 m.M31 = a.M31*b.M11 + a.M32*b.M21 + a.M33*b.M31 + a.M34*b.M41;
\r
598 m.M32 = a.M31*b.M12 + a.M32*b.M22 + a.M33*b.M32 + a.M34*b.M42;
\r
599 m.M33 = a.M31*b.M13 + a.M32*b.M23 + a.M33*b.M33 + a.M34*b.M43;
\r
600 m.M34 = a.M31*b.M14 + a.M32*b.M24 + a.M33*b.M34 + a.M34*b.M44;
\r
602 m.M41 = a.M41*b.M11 + a.M42*b.M21 + a.M43*b.M31 + a.M44*b.M41;
\r
603 m.M42 = a.M41*b.M12 + a.M42*b.M22 + a.M43*b.M32 + a.M44*b.M42;
\r
604 m.M43 = a.M41*b.M13 + a.M42*b.M23 + a.M43*b.M33 + a.M44*b.M43;
\r
605 m.M44 = a.M41*b.M14 + a.M42*b.M24 + a.M43*b.M34 + a.M44*b.M44;
\r
611 public partial struct Vertex : IComparable<Vertex>
\r
618 //public int Count;
\r
619 //public Weights[] Weights;
\r
621 public Vertex(Point3 pos, Point4 wgt, UInt32 idx, Point3 nrm, Point2 tex)
\r
630 public int CompareTo(Vertex o)
\r
632 if(Pos.x < o.Pos.x) return -1; if(Pos.x > o.Pos.x) return 1;
\r
633 if(Pos.y < o.Pos.y) return -1; if(Pos.y > o.Pos.y) return 1;
\r
634 if(Pos.z < o.Pos.z) return -1; if(Pos.z > o.Pos.z) return 1;
\r
635 if(Nrm.x < o.Nrm.x) return -1; if(Nrm.x > o.Nrm.x) return 1;
\r
636 if(Nrm.y < o.Nrm.y) return -1; if(Nrm.y > o.Nrm.y) return 1;
\r
637 if(Nrm.z < o.Nrm.z) return -1; if(Nrm.z > o.Nrm.z) return 1;
\r
638 if(Tex.x < o.Tex.x) return -1; if(Tex.x > o.Tex.x) return 1;
\r
639 if(Tex.y < o.Tex.y) return -1; if(Tex.y > o.Tex.y) return 1;
\r
640 if(Wgt.x < o.Wgt.x) return -1; if(Wgt.x > o.Wgt.x) return 1;
\r
641 if(Wgt.y < o.Wgt.y) return -1; if(Wgt.y > o.Wgt.y) return 1;
\r
642 if(Wgt.z < o.Wgt.z) return -1; if(Wgt.z > o.Wgt.z) return 1;
\r
643 if(Wgt.w < o.Wgt.w) return -1; if(Wgt.w > o.Wgt.w) return 1;
\r
644 if(Idx < o.Idx) return -1; if(Idx > o.Idx) return 1;
\r
648 public override int GetHashCode()
\r
650 return Pos.x.GetHashCode() ^ Pos.y.GetHashCode() ^ Pos.z.GetHashCode()
\r
651 ^ Nrm.x.GetHashCode() ^ Nrm.y.GetHashCode() ^ Nrm.z.GetHashCode()
\r
652 ^ Tex.x.GetHashCode() ^ Tex.y.GetHashCode() ^ Wgt.w.GetHashCode()
\r
653 ^ Wgt.x.GetHashCode() ^ Wgt.y.GetHashCode() ^ Wgt.z.GetHashCode()
\r
654 ^ Idx.GetHashCode();
\r
657 public override bool Equals(object obj)
\r
659 Vertex o = (Vertex)obj;
\r
661 return Pos.x==o.Pos.x && Pos.y==o.Pos.y && Pos.z==o.Pos.z
\r
662 && Nrm.x==o.Nrm.x && Nrm.y==o.Nrm.y && Nrm.z==o.Nrm.z
\r
663 && Tex.x==o.Tex.x && Tex.y==o.Tex.y && Wgt.w==o.Wgt.w
\r
664 && Wgt.x==o.Wgt.x && Wgt.y==o.Wgt.y && Wgt.z==o.Wgt.z
\r
670 public struct Weights
\r
673 public float Weight;
\r