OSDN Git Service

for metaseq v4.0
[tdcgexplorer/tso2mqo.git] / MqoFile.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text;
5 using System.Text.RegularExpressions;
6
7 namespace Tso2MqoGui
8 {
9     public class MqoFile
10     {
11         private delegate bool SectionHandler(string[] tokens);
12
13         private static char[] delimiters2 = new char[] { ' ', '\t', '(', ')' };
14
15         private string file;
16         private StreamReader sr;
17         private MqoScene scene;
18         private List<MqoMaterial> materials;
19         private List<MqoObject> objects = new List<MqoObject>();
20         private MqoObject current;
21
22         public MqoScene Scene { get { return scene; } }
23         public List<MqoMaterial> Materials { get { return materials; } }
24         public List<MqoObject> Objects { get { return objects; } }
25
26         public void Load(string file)
27         {
28             using (FileStream fs = File.OpenRead(file))
29             {
30                 this.file = file;
31                 sr = new StreamReader(fs, Encoding.Default);
32                 ReadAll();
33             }
34         }
35
36         public void ReadAll()
37         {
38             DoRead(SectionRoot);
39         }
40
41         private static string[] SplitString(string s)
42         {
43             List<string> tokens = new List<string>();
44             StringBuilder sb = new StringBuilder(s.Length);
45             bool str = false;
46             bool escape = false;
47             bool bracket = false;
48             s = s.Trim(' ', '\t', '\r', '\n');
49
50             foreach (char i in s)
51             {
52                 if (escape)
53                 {
54                     sb.Append(i);
55                     escape = false;
56                     continue;
57                 }
58
59
60                 switch (i)
61                 {
62                     case '\\':
63                         if (str) sb.Append(i);
64                         else escape = true;
65                         break;
66                     case ' ':
67                     case '\t':
68                         if (bracket) { sb.Append(i); }
69                         else if (str) { sb.Append(i); }
70                         else if (sb.Length > 0) { tokens.Add(sb.ToString()); sb.Length = 0; }
71                         break;
72                     case '(':
73                         sb.Append(i);
74                         if (!str)
75                             bracket = true;
76                         break;
77                     case ')':
78                         sb.Append(i);
79                         if (!str)
80                             bracket = false;
81                         break;
82                     case '\"':
83                         sb.Append(i);
84                         str = !str;
85                         break;
86                     default:
87                         sb.Append(i);
88                         break;
89                 }
90             }
91
92             if (sb.Length > 0)
93                 tokens.Add(sb.ToString());
94
95             return tokens.ToArray();
96         }
97
98         private void DoRead(SectionHandler h)
99         {
100             for (int no = 1; ; ++no)
101             {
102                 string line = sr.ReadLine();
103
104                 if (line == null)
105                     break;
106
107                 line = line.Trim();
108                 string[] tokens = SplitString(line);
109
110                 try
111                 {
112                     if (tokens.Length == 0)
113                         continue;
114
115                     if (!h(tokens))
116                         break;
117                 }
118                 catch (Exception exception)
119                 {
120                     string msg = string.Format("File format error: {0} \"{1}\"", no, line);
121                     throw new Exception(msg, exception);
122                 }
123             }
124         }
125
126         public void Error(string[] tokens)
127         {
128             throw new Exception("File Format Error: \"" + string.Concat(tokens) + "\"");
129         }
130
131         private bool SectionRoot(string[] tokens)
132         {
133             switch (tokens[0])
134             {
135                 case "Metasequoia": ParseMetasequoia(tokens); return true;
136                 case "Format": ParseFormat(tokens); return true;
137                 case "Thumbnail": ParseThumbnail(tokens); return true;
138                 case "Scene": ParseScene(tokens); return true;
139                 case "Material": ParseMaterial(tokens); return true;
140                 case "Object": ParseObject(tokens); return true;
141                 case "Eof":
142                     return false;
143                 default:
144                     return true;
145             }
146         }
147
148         private bool SectionThumbnail(string[] tokens)
149         {
150             switch (tokens[0])
151             {
152                 case "}":
153                     return false;
154                 default:
155                     return true;
156             }
157         }
158
159         private bool SectionScene(string[] tokens)
160         {
161             scene = new MqoScene();
162
163             switch (tokens[0])
164             {
165                 case "pos": scene.pos = Point3.Parse(tokens, 1); return true;
166                 case "lookat": scene.lookat = Point3.Parse(tokens, 1); return true;
167                 case "head": scene.head = float.Parse(tokens[1]); return true;
168                 case "pich": scene.pich = float.Parse(tokens[1]); return true;
169                 case "ortho": scene.ortho = float.Parse(tokens[1]); return true;
170                 case "zoom2": scene.zoom2 = float.Parse(tokens[1]); return true;
171                 case "amb": scene.amb = Color3.Parse(tokens, 1); return true;
172                 case "dirlights": ParseDirlights(tokens); return true;
173                 case "}":
174                     return false;
175                 default:
176                     return true;
177             }
178         }
179
180         private bool SectionDirlights(string[] tokens)
181         {
182             switch (tokens[0])
183             {
184                 case "light": ParseLight(tokens); return true;
185                 case "}":
186                     return false;
187                 default:
188                     return true;
189             }
190         }
191
192         private bool SectionLight(string[] tokens)
193         {
194             switch (tokens[0])
195             {
196                 case "}":
197                     return false;
198                 default:
199                     return true;
200             }
201         }
202
203         private static string[] SplitParam(string s)
204         {
205             return s.Split(delimiters2, StringSplitOptions.RemoveEmptyEntries);
206         }
207
208         private bool SectionMaterial(string[] tokens)
209         {
210             if (tokens[0] == "}")
211                 return false;
212
213             StringBuilder sb = new StringBuilder();
214
215             foreach (string i in tokens)
216                 sb.Append(' ').Append(i);
217
218             string line = sb.ToString().Trim();
219             MqoMaterial m = new MqoMaterial(tokens[0].Trim('"'));
220             tokens = SplitString(line);
221             materials.Add(m);
222
223             for (int i = 1; i < tokens.Length; ++i)
224             {
225                 string t = tokens[i];
226                 string t2 = t.ToLower();
227
228                 if (t2.StartsWith("shader(")) m.shader = int.Parse(SplitParam(t)[1]);
229                 else if (t2.StartsWith("col(")) m.col = Color3.Parse(SplitParam(t), 1);
230                 else if (t2.StartsWith("dif(")) m.dif = float.Parse(SplitParam(t)[1]);
231                 else if (t2.StartsWith("amb(")) m.amb = float.Parse(SplitParam(t)[1]);
232                 else if (t2.StartsWith("emi(")) m.emi = float.Parse(SplitParam(t)[1]);
233                 else if (t2.StartsWith("spc(")) m.spc = float.Parse(SplitParam(t)[1]);
234                 else if (t2.StartsWith("power(")) m.power = float.Parse(SplitParam(t)[1]);
235                 else if (t2.StartsWith("tex(")) m.tex = t.Substring(3).Trim('(', ')', '"');
236             }
237
238             return true;
239         }
240
241         private bool SectionObject(string[] tokens)
242         {
243             switch (tokens[0])
244             {
245                 case "visible": current.visible = int.Parse(tokens[1]); return true;
246                 case "locking": current.locking = int.Parse(tokens[1]); return true;
247                 case "shading": current.shading = int.Parse(tokens[1]); return true;
248                 case "facet": current.facet = float.Parse(tokens[1]); return true;
249                 case "color": current.color = Color3.Parse(tokens, 1); return true;
250                 case "color_type": current.color_type = int.Parse(tokens[1]); return true;
251                 case "vertex": ParseVertex(tokens); return true;
252                 case "face": ParseFace(tokens); return true;
253                 case "}":
254                     return false;
255                 default:
256                     return true;
257             }
258         }
259
260         private bool SectionVertex(string[] tokens)
261         {
262             if (tokens[0] == "}")
263                 return false;
264
265             current.vertices.Add(Point3.Parse(tokens, 0));
266
267             return true;
268         }
269
270         private bool SectionFace(string[] tokens)
271         {
272             if (tokens[0] == "}")
273                 return false;
274
275             int nface = int.Parse(tokens[0]);
276             {
277                 StringBuilder sb = new StringBuilder();
278                 foreach (string i in tokens)
279                     sb.Append(' ').Append(i);
280                 string line = sb.ToString().Trim();
281                 tokens = SplitString(line);
282             }
283             switch (nface)
284             {
285                 case 3:
286                     {
287                         MqoFace f = new MqoFace();
288
289                         for (int i = 1; i < tokens.Length; ++i)
290                         {
291                             string t = tokens[i];
292                             string t2 = t.ToLower();
293
294                             if (t2.StartsWith("v("))
295                             {
296                                 string[] t3 = SplitParam(t);
297                                 f.a = ushort.Parse(t3[1]);
298                                 f.b = ushort.Parse(t3[2]);
299                                 f.c = ushort.Parse(t3[3]);
300                             }
301                             else
302                                 if (t2.StartsWith("m("))
303                                 {
304                                     string[] t3 = SplitParam(t);
305                                     f.mtl = ushort.Parse(t3[1]);
306                                 }
307                                 else
308                                     if (t2.StartsWith("uv("))
309                                     {
310                                         string[] t3 = SplitParam(t);
311                                         f.ta = Point2.Parse(t3, 1);
312                                         f.tb = Point2.Parse(t3, 3);
313                                         f.tc = Point2.Parse(t3, 5);
314                                     }
315                         }
316                         current.faces.Add(f);
317                     }
318                     break;
319                 case 4:
320                     {
321                         MqoFace f = new MqoFace();
322                         MqoFace f2 = new MqoFace();
323
324                         for (int i = 1; i < tokens.Length; ++i)
325                         {
326                             string t = tokens[i];
327                             string t2 = t.ToLower();
328
329                             if (t2.StartsWith("v("))
330                             {
331                                 string[] t3 = SplitParam(t);
332                                 f.a = ushort.Parse(t3[1]);
333                                 f.b = ushort.Parse(t3[2]);
334                                 f.c = ushort.Parse(t3[3]);
335                                 f2.a = f.a;
336                                 f2.b = f.c;
337                                 f2.c = ushort.Parse(t3[4]);
338                             }
339                             else
340                                 if (t2.StartsWith("m("))
341                                 {
342                                     string[] t3 = SplitParam(t);
343                                     f.mtl = ushort.Parse(t3[1]);
344                                     f2.mtl = f.mtl;
345                                 }
346                                 else
347                                     if (t2.StartsWith("uv("))
348                                     {
349                                         string[] t3 = SplitParam(t);
350                                         f.ta = Point2.Parse(t3, 1);
351                                         f.tb = Point2.Parse(t3, 3);
352                                         f.tc = Point2.Parse(t3, 5);
353                                         f2.ta = f.ta;
354                                         f2.tb = f.tc;
355                                         f2.tc = Point2.Parse(t3, 7);
356                                     }
357                         }
358                         current.faces.Add(f);
359                         current.faces.Add(f2);
360                     }
361                     break;
362             }
363             return true;
364         }
365
366         //----- Root elements ----------------------------------------------
367         private void ParseMetasequoia(string[] tokens)
368         {
369             // Metasequoia Document
370             if (tokens[1] != "Document")
371                 Error(tokens);
372         }
373
374         private void ParseFormat(string[] tokens)
375         {
376             // @since v2.2
377             // Format Text Ver 1.0
378             // @since v4.0
379             // Format Text Ver 1.1
380             if (tokens[1] != "Text")
381                 Error(tokens);
382             if (tokens[2] != "Ver")
383                 Error(tokens);
384             if (tokens[3] != "1.0" && tokens[3] != "1.1")
385                     Error(tokens);
386         }
387
388         private void ParseThumbnail(string[] tokens)
389         {
390             // Thumbnail 128 128 24 rgb raw {
391             // ...
392             // }
393             if (tokens[6] != "{") Error(tokens);
394
395             DoRead(SectionThumbnail);
396         }
397
398         private void ParseScene(string[] tokens)
399         {
400             if (tokens[1].ToLower() != "{") Error(tokens);
401
402             DoRead(SectionScene);
403         }
404
405         private void ParseDirlights(string[] tokens)
406         {
407             // dirlights 1 {
408             // ...
409             // }
410             if (tokens[2].ToLower() != "{") Error(tokens);
411
412             DoRead(SectionDirlights);
413         }
414
415         private void ParseLight(string[] tokens)
416         {
417             // light {
418             // ...
419             // }
420             if (tokens[1].ToLower() != "{") Error(tokens);
421
422             DoRead(SectionLight);
423         }
424
425         private void ParseMaterial(string[] tokens)
426         {
427             if (tokens[2].ToLower() != "{") Error(tokens);
428
429             materials = new List<MqoMaterial>(int.Parse(tokens[1]));
430             DoRead(SectionMaterial);
431         }
432
433         private void ParseObject(string[] tokens)
434         {
435             if (tokens[2].ToLower() != "{") Error(tokens);
436
437             current = new MqoObject(tokens[1].Trim('"'));
438             objects.Add(current);
439             DoRead(SectionObject);
440         }
441
442         private void ParseVertex(string[] tokens)
443         {
444             if (tokens[2].ToLower() != "{") Error(tokens);
445
446             current.vertices = new List<Point3>(int.Parse(tokens[1]));
447             DoRead(SectionVertex);
448         }
449
450         private void ParseFace(string[] tokens)
451         {
452             if (tokens[2].ToLower() != "{") Error(tokens);
453
454             current.faces = new List<MqoFace>(int.Parse(tokens[1]));
455             DoRead(SectionFace);
456         }
457     }
458
459     public class MqoScene
460     {
461         public Point3 pos;
462         public Point3 lookat;
463         public float head;
464         public float pich;
465         public float ortho;
466         public float zoom2;
467         public Color3 amb;
468     }
469
470     public class MqoMaterial
471     {
472         public string name;
473         public int shader;
474         public Color3 col;
475         public float dif;
476         public float amb;
477         public float emi;
478         public float spc;
479         public float power;
480         public string tex;
481
482         public MqoMaterial() { }
483         public MqoMaterial(string n) { name = n; }
484     }
485
486     public class MqoObject
487     {
488         public string name;
489         public int visible;
490         public int locking;
491         public int shading;
492         public float facet;
493         public Color3 color;
494         public int color_type;
495         public List<Point3> vertices;
496         public List<MqoFace> faces;
497
498         public MqoObject() { }
499         public MqoObject(string n) { name = n; }
500     }
501
502     public class MqoFace
503     {
504         public ushort a, b, c, mtl;
505         public Point2 ta, tb, tc;
506
507         public MqoFace()
508         {
509         }
510
511         public MqoFace(ushort a, ushort b, ushort c, ushort mtl, Point2 ta, Point2 tb, Point2 tc)
512         {
513             this.a = a;
514             this.b = b;
515             this.c = c;
516             this.mtl = mtl;
517             this.ta = ta;
518             this.tb = tb;
519             this.tc = tc;
520         }
521     }
522 }