OSDN Git Service

cfcb8413406439ef7202dd2ea25690e65f14e311
[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].ToLower())
134             {
135                 case "metasequoia": ParseMetasequoia(tokens); return true;
136                 case "format": ParseFormat(tokens); return true;
137                 case "scene": ParseScene(tokens); return true;
138                 case "material": ParseMaterial(tokens); return true;
139                 case "object": ParseObject(tokens); return true;
140                 case "eof": return false;
141                 default: return true;
142             }
143         }
144
145         private bool SectionScene(string[] tokens)
146         {
147             scene = new MqoScene();
148
149             switch (tokens[0].ToLower())
150             {
151                 case "pos": scene.pos = Point3.Parse(tokens, 1); return true;
152                 case "lookat": scene.lookat = Point3.Parse(tokens, 1); return true;
153                 case "head": scene.head = float.Parse(tokens[1]); return true;
154                 case "pich": scene.pich = float.Parse(tokens[1]); return true;
155                 case "ortho": scene.ortho = float.Parse(tokens[1]); return true;
156                 case "zoom2": scene.zoom2 = float.Parse(tokens[1]); return true;
157                 case "amb": scene.amb = Color3.Parse(tokens, 1); return true;
158                 case "}": return false;
159                 default: return true;
160             }
161         }
162
163         private static string[] SplitParam(string s)
164         {
165             return s.Split(delimiters2, StringSplitOptions.RemoveEmptyEntries);
166         }
167
168         private bool SectionMaterial(string[] tokens)
169         {
170             if (tokens[0] == "}")
171                 return false;
172
173             StringBuilder sb = new StringBuilder();
174
175             foreach (string i in tokens)
176                 sb.Append(' ').Append(i);
177
178             string line = sb.ToString().Trim();
179             MqoMaterial m = new MqoMaterial(tokens[0].Trim('"'));
180             tokens = SplitString(line);
181             materials.Add(m);
182
183             for (int i = 1; i < tokens.Length; ++i)
184             {
185                 string t = tokens[i];
186                 string t2 = t.ToLower();
187
188                 if (t2.StartsWith("shader(")) m.shader = int.Parse(SplitParam(t)[1]);
189                 else if (t2.StartsWith("col(")) m.col = Color3.Parse(SplitParam(t), 1);
190                 else if (t2.StartsWith("dif(")) m.dif = float.Parse(SplitParam(t)[1]);
191                 else if (t2.StartsWith("amb(")) m.amb = float.Parse(SplitParam(t)[1]);
192                 else if (t2.StartsWith("emi(")) m.emi = float.Parse(SplitParam(t)[1]);
193                 else if (t2.StartsWith("spc(")) m.spc = float.Parse(SplitParam(t)[1]);
194                 else if (t2.StartsWith("power(")) m.power = float.Parse(SplitParam(t)[1]);
195                 else if (t2.StartsWith("tex(")) m.tex = t.Substring(3).Trim('(', ')', '"');
196             }
197
198             return true;
199         }
200
201         private bool SectionObject(string[] tokens)
202         {
203             switch (tokens[0].ToLower())
204             {
205                 case "visible": current.visible = int.Parse(tokens[1]); return true;
206                 case "locking": current.locking = int.Parse(tokens[1]); return true;
207                 case "shading": current.shading = int.Parse(tokens[1]); return true;
208                 case "facet": current.facet = float.Parse(tokens[1]); return true;
209                 case "color": current.color = Color3.Parse(tokens, 1); return true;
210                 case "color_type": current.color_type = int.Parse(tokens[1]); return true;
211                 case "vertex": ParseVertex(tokens); return true;
212                 case "face": ParseFace(tokens); return true;
213                 case "}": return false;
214                 default: return true;
215             }
216         }
217
218         private bool SectionVertex(string[] tokens)
219         {
220             if (tokens[0] == "}")
221                 return false;
222
223             current.vertices.Add(Point3.Parse(tokens, 0));
224
225             return true;
226         }
227
228         private bool SectionFace(string[] tokens)
229         {
230             if (tokens[0] == "}")
231                 return false;
232
233             int nface = int.Parse(tokens[0]);
234             {
235                 StringBuilder sb = new StringBuilder();
236                 foreach (string i in tokens)
237                     sb.Append(' ').Append(i);
238                 string line = sb.ToString().Trim();
239                 tokens = SplitString(line);
240             }
241             switch (nface)
242             {
243                 case 3:
244                     {
245                         MqoFace f = new MqoFace();
246
247                         for (int i = 1; i < tokens.Length; ++i)
248                         {
249                             string t = tokens[i];
250                             string t2 = t.ToLower();
251
252                             if (t2.StartsWith("v("))
253                             {
254                                 string[] t3 = SplitParam(t);
255                                 f.a = ushort.Parse(t3[1]);
256                                 f.b = ushort.Parse(t3[2]);
257                                 f.c = ushort.Parse(t3[3]);
258                             }
259                             else
260                                 if (t2.StartsWith("m("))
261                                 {
262                                     string[] t3 = SplitParam(t);
263                                     f.mtl = ushort.Parse(t3[1]);
264                                 }
265                                 else
266                                     if (t2.StartsWith("uv("))
267                                     {
268                                         string[] t3 = SplitParam(t);
269                                         f.ta = Point2.Parse(t3, 1);
270                                         f.tb = Point2.Parse(t3, 3);
271                                         f.tc = Point2.Parse(t3, 5);
272                                     }
273                         }
274                         current.faces.Add(f);
275                     }
276                     break;
277                 case 4:
278                     {
279                         MqoFace f = new MqoFace();
280                         MqoFace f2 = new MqoFace();
281
282                         for (int i = 1; i < tokens.Length; ++i)
283                         {
284                             string t = tokens[i];
285                             string t2 = t.ToLower();
286
287                             if (t2.StartsWith("v("))
288                             {
289                                 string[] t3 = SplitParam(t);
290                                 f.a = ushort.Parse(t3[1]);
291                                 f.b = ushort.Parse(t3[2]);
292                                 f.c = ushort.Parse(t3[3]);
293                                 f2.a = f.a;
294                                 f2.b = f.c;
295                                 f2.c = ushort.Parse(t3[4]);
296                             }
297                             else
298                                 if (t2.StartsWith("m("))
299                                 {
300                                     string[] t3 = SplitParam(t);
301                                     f.mtl = ushort.Parse(t3[1]);
302                                     f2.mtl = f.mtl;
303                                 }
304                                 else
305                                     if (t2.StartsWith("uv("))
306                                     {
307                                         string[] t3 = SplitParam(t);
308                                         f.ta = Point2.Parse(t3, 1);
309                                         f.tb = Point2.Parse(t3, 3);
310                                         f.tc = Point2.Parse(t3, 5);
311                                         f2.ta = f.ta;
312                                         f2.tb = f.tc;
313                                         f2.tc = Point2.Parse(t3, 7);
314                                     }
315                         }
316                         current.faces.Add(f);
317                         current.faces.Add(f2);
318                     }
319                     break;
320             }
321             return true;
322         }
323
324         //----- Root elements ----------------------------------------------
325         private void ParseMetasequoia(string[] tokens)
326         {
327             if (tokens[1].ToLower() != "document") Error(tokens);
328         }
329
330         private void ParseFormat(string[] tokens)
331         {
332             if (tokens[1].ToLower() != "text") Error(tokens);
333             if (tokens[2].ToLower() != "ver") Error(tokens);
334             if (tokens[3].ToLower() != "1.0") Error(tokens);
335         }
336
337         private void ParseScene(string[] tokens)
338         {
339             if (tokens[1].ToLower() != "{") Error(tokens);
340
341             DoRead(SectionScene);
342         }
343
344         private void ParseMaterial(string[] tokens)
345         {
346             if (tokens[2].ToLower() != "{") Error(tokens);
347
348             materials = new List<MqoMaterial>(int.Parse(tokens[1]));
349             DoRead(SectionMaterial);
350         }
351
352         private void ParseObject(string[] tokens)
353         {
354             if (tokens[2].ToLower() != "{") Error(tokens);
355
356             current = new MqoObject(tokens[1].Trim('"'));
357             objects.Add(current);
358             DoRead(SectionObject);
359         }
360
361         private void ParseVertex(string[] tokens)
362         {
363             if (tokens[2].ToLower() != "{") Error(tokens);
364
365             current.vertices = new List<Point3>(int.Parse(tokens[1]));
366             DoRead(SectionVertex);
367         }
368
369         private void ParseFace(string[] tokens)
370         {
371             if (tokens[2].ToLower() != "{") Error(tokens);
372
373             current.faces = new List<MqoFace>(int.Parse(tokens[1]));
374             DoRead(SectionFace);
375         }
376     }
377
378     public class MqoScene
379     {
380         public Point3 pos;
381         public Point3 lookat;
382         public float head;
383         public float pich;
384         public float ortho;
385         public float zoom2;
386         public Color3 amb;
387     }
388
389     public class MqoMaterial
390     {
391         public string name;
392         public int shader;
393         public Color3 col;
394         public float dif;
395         public float amb;
396         public float emi;
397         public float spc;
398         public float power;
399         public string tex;
400
401         public MqoMaterial() { }
402         public MqoMaterial(string n) { name = n; }
403     }
404
405     public class MqoObject
406     {
407         public string name;
408         public int visible;
409         public int locking;
410         public int shading;
411         public float facet;
412         public Color3 color;
413         public int color_type;
414         public List<Point3> vertices;
415         public List<MqoFace> faces;
416
417         public MqoObject() { }
418         public MqoObject(string n) { name = n; }
419     }
420
421     public class MqoFace
422     {
423         public ushort a, b, c, mtl;
424         public Point2 ta, tb, tc;
425
426         public MqoFace()
427         {
428         }
429
430         public MqoFace(ushort a, ushort b, ushort c, ushort mtl, Point2 ta, Point2 tb, Point2 tc)
431         {
432             this.a = a;
433             this.b = b;
434             this.c = c;
435             this.mtl = mtl;
436             this.ta = ta;
437             this.tb = tb;
438             this.tc = tc;
439         }
440     }
441 }