OSDN Git Service

implemnet RigidBody
[meshio/pymeshio.git] / pymeshio / mqo.py
1 # coding: utf-8\r
2 """ \r
3 MQOの読み込み\r
4 http://www.metaseq.net/metaseq/format.html\r
5 """\r
6 \r
7 import os\r
8 import sys\r
9 import math\r
10 \r
11 \r
12 class RGBA(object):\r
13     """mqo color"""\r
14     __slots__=['r', 'g', 'b', 'a']\r
15     def __init__(self, r=0, g=0, b=0, a=0):\r
16         self.r=r\r
17         self.g=g\r
18         self.b=b\r
19         self.a=a\r
20 \r
21     def __getitem__(self, key):\r
22         if key==0:\r
23             return self.r\r
24         elif key==1:\r
25             return self.g\r
26         elif key==2:\r
27             return self.b\r
28         elif key==3:\r
29             return self.a\r
30         else:\r
31             assert(False)\r
32 \r
33 \r
34 class Vector3(object):\r
35     """3D coordinate"""\r
36     __slots__=['x', 'y', 'z']\r
37     def __init__(self, x=0, y=0, z=0):\r
38         self.x=x\r
39         self.y=y\r
40         self.z=z\r
41 \r
42     def __str__(self):\r
43         return "[%f, %f, %f]" % (self.x, self.y, self.z)\r
44 \r
45     def __sub__(self, rhs):\r
46         return Vector3(self.x-rhs.x, self.y-rhs.y, self.z-rhs.z)\r
47 \r
48     def getSqNorm(self):\r
49         return self.x*self.x + self.y*self.y + self.z*self.z\r
50 \r
51     def getNorm(self):\r
52         return math.sqrt(self.getSqNorm())\r
53 \r
54     def normalize(self):\r
55         factor=1.0/self.getNorm()\r
56         self.x*=factor\r
57         self.y*=factor\r
58         self.z*=factor\r
59         return self\r
60 \r
61     def to_a(self):\r
62         return [self.x, self.y, self.z]\r
63 \r
64     @staticmethod\r
65     def dot(lhs, rhs):\r
66         """dot(inner) product"""\r
67         return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z\r
68 \r
69     @staticmethod\r
70     def cross(lhs, rhs):\r
71         """cross(outer) product"""\r
72         return Vector3(\r
73                 lhs.y*rhs.z - rhs.y*lhs.z,\r
74                 lhs.z*rhs.x - rhs.z*lhs.x,\r
75                 lhs.x*rhs.y - rhs.x*lhs.y,\r
76                 )\r
77 \r
78 \r
79 class Vector2(object):\r
80     """2d coordinate"""\r
81     __slots__=['x', 'y']\r
82     def __init__(self, x=0, y=0):\r
83         self.x=x\r
84         self.y=y\r
85 \r
86     def __str__(self):\r
87         return "[%f, %f]" % (self.x, self.y)\r
88 \r
89     def __sub__(self, rhs):\r
90         return Vector3(self.x-rhs.x, self.y-rhs.y)\r
91 \r
92     @staticmethod\r
93     def cross(lhs, rhs):\r
94         """cross(outer) product"""\r
95         return lhs.x*rhs.y-lhs.y*rhs.x\r
96 \r
97 \r
98 """\r
99 MQO loader\r
100 """\r
101 class Material(object):\r
102     """mqo material\r
103 \r
104     Attributes:\r
105         name: cp932\r
106         shader: \r
107         color: rgba\r
108         diffuse:\r
109         ambient:\r
110         emit:\r
111         specular:\r
112         power:\r
113         tex: cp932 windows file path\r
114     """\r
115     __slots__=[\r
116             "name", "shader", "color", "diffuse", \r
117             "ambient", "emit", "specular", "power",\r
118             "tex",\r
119             ]\r
120     def __init__(self, name):\r
121         self.name=name\r
122         self.shader=3\r
123         self.color=RGBA(0.5, 0.5, 0.5, 1.0)\r
124         self.diffuse=1.0\r
125         self.ambient=0.0\r
126         self.emit=0.0\r
127         self.specular=0.0\r
128         self.power=5.0\r
129         self.tex=""\r
130 \r
131     def getName(self): return self.name\r
132     def getTexture(self): return self.tex\r
133 \r
134     def parse(self, line):\r
135         offset=0\r
136         while True:\r
137             leftParenthesis=line.find("(", offset)\r
138             if leftParenthesis==-1:\r
139                 break\r
140             key=line[offset:leftParenthesis]\r
141             rightParenthesis=line.find(")", leftParenthesis+1)\r
142             if rightParenthesis==-1:\r
143                 raise ValueError("assert")\r
144 \r
145             param=line[leftParenthesis+1:rightParenthesis]\r
146             if key=="shader":\r
147                 self.shader=int(param)\r
148             elif key=="col":\r
149                 self.color=RGBA(*[float(e) for e in param.split()])\r
150             elif key=="dif":\r
151                 self.diffuse=float(param)\r
152             elif key=="amb":\r
153                 self.ambient=float(param)\r
154             elif key=="emi":\r
155                 self.emit=float(param)\r
156             elif key=="spc":\r
157                 self.specular=float(param)\r
158             elif key=="power":\r
159                 self.power=float(param)\r
160             elif key=="tex":\r
161                 self.tex=param[1:-1]\r
162             else:\r
163                 print(\r
164                         "%s#parse" % self.name, \r
165                         "unknown key: %s" %  key\r
166                         )\r
167 \r
168             offset=rightParenthesis+2\r
169 \r
170     def __str__(self):\r
171         return "<Material %s shader: %d [%f, %f, %f, %f] %f>" % (\r
172                 self.name, self.shader,\r
173                 self.color[0], self.color[1], self.color[2], self.color[3],\r
174                 self.diffuse)\r
175 \r
176 \r
177 class Obj(object):\r
178     """mqo object\r
179 \r
180     Attributes:\r
181         name: cp932\r
182         depth: object hierarchy \r
183         folding: \r
184         scale:\r
185         rotation:\r
186         translation:\r
187         visible:\r
188         locking:\r
189         shading:\r
190         facet: smoothing threshold\r
191         color:\r
192         color_type:\r
193         mirror: mirroring\r
194         mirror_axis:\r
195         vertices:\r
196         faces:\r
197         edges:\r
198         smoothing:\r
199     """\r
200     __slots__=["name", "depth", "folding", \r
201             "scale", "rotation", "translation",\r
202             "visible", "locking", "shading", "facet",\r
203             "color", "color_type", "mirror", "mirror_axis",\r
204             "vertices", "faces", "edges", "smoothing",\r
205             ]\r
206 \r
207     def __init__(self, name):\r
208         self.name=name\r
209         self.vertices=[]\r
210         self.faces=[]\r
211         self.edges=[]\r
212         self.depth=0\r
213         self.folding=0\r
214         self.scale=[1, 1, 1]\r
215         self.rotation=[0, 0, 0]\r
216         self.translation=[0, 0, 0]\r
217         self.visible=15\r
218         self.locking=0\r
219         self.shading=0\r
220         self.facet=59.5\r
221         self.color=[1, 1, 1]\r
222         self.color_type=0\r
223         self.mirror=0\r
224         self.smoothing=0\r
225 \r
226     def getName(self): return self.name\r
227 \r
228     def addVertex(self, x, y, z):\r
229         self.vertices.append(Vector3(x, y, z))\r
230 \r
231     def addFace(self, face):\r
232         if face.index_count==2:\r
233             self.edges.append(face)\r
234         else:\r
235             self.faces.append(face)\r
236 \r
237     def __str__(self):\r
238         return "<Object %s, %d vertices, %d faces>" % (\r
239                 self.name, len(self.vertices), len(self.faces))\r
240 \r
241 \r
242 class Face(object):\r
243     """mqo face\r
244 \r
245     Attributes:\r
246         index_count: 2 or 3 or 4\r
247         indices: index x index_count\r
248         material_index:\r
249         col: vertex_color x index_count\r
250         uv: Vector2 x index_count\r
251     """\r
252     __slots__=[\r
253             "index_count",\r
254             "indices", "material_index", "col", "uv",\r
255             ]\r
256     def __init__(self, index_count, line):\r
257         if index_count<2 or index_count>4:\r
258             raise ValueError("invalid vertex count: %d" % index_count)\r
259         self.material_index=0\r
260         self.col=[]\r
261         self.uv=[Vector2(0, 0)]*4\r
262         self.index_count=index_count\r
263         offset=0\r
264         while True:\r
265             leftParenthesis=line.find("(", offset)\r
266             if leftParenthesis==-1:\r
267                 break\r
268             key=line[offset:leftParenthesis]\r
269             rightParenthesis=line.find(")", leftParenthesis+1)\r
270             if rightParenthesis==-1:\r
271                 raise ValueError("assert")\r
272             params=line[leftParenthesis+1:rightParenthesis].split()\r
273             if key=="V":\r
274                 self.indices=[int(e) for e in params]\r
275             elif key=="M":\r
276                 self.material_index=int(params[0])\r
277             elif key=="UV":\r
278                 uv_list=[float(e) for e in params]\r
279                 self.uv=[]\r
280                 for i in range(0, len(uv_list), 2):\r
281                     self.uv.append(Vector2(uv_list[i], uv_list[i+1]))\r
282             elif key=="COL":\r
283                 for n in params:\r
284                     d=int(n)\r
285                     # R\r
286                     d, m=divmod(d, 256)\r
287                     self.col.append(m)\r
288                     # G\r
289                     d, m=divmod(d, 256)\r
290                     self.col.append(m)\r
291                     # B\r
292                     d, m=divmod(d, 256)\r
293                     self.col.append(m)\r
294                     # A\r
295                     d, m=divmod(d, 256)\r
296                     self.col.append(m)\r
297             else:\r
298                 print("Face#__init__:unknown key: %s" % key)\r
299 \r
300             offset=rightParenthesis+2\r
301 \r
302     def getIndex(self, i): return self.indices[i]\r
303     def getUV(self, i): return self.uv[i] if i<len(self.uv) else Vector2(0, 0)\r
304 \r
305 \r
306 def withio(method):\r
307     def new(self, path):\r
308         print(sys.version_info[0])\r
309         if sys.version_info[0]<3:\r
310             self.io=open(path)\r
311         else:\r
312             self.io=open(path, encoding='cp932')\r
313         result=method(self)\r
314         self.io.close()\r
315         self.io=None\r
316         return result\r
317     return new\r
318 \r
319 \r
320 class IO(object):\r
321     """mqo loader\r
322     """\r
323     __slots__=[\r
324             "has_mikoto",\r
325             "eof", "io", "lines",\r
326             "materials", "objects",\r
327             ]\r
328     def __init__(self):\r
329         self.has_mikoto=False\r
330         self.eof=False\r
331         self.io=None\r
332         self.lines=0\r
333         self.materials=[]\r
334         self.objects=[]\r
335 \r
336     def __str__(self):\r
337         return "<MQO %d lines, %d materials, %d objects>" % (\r
338                 self.lines, len(self.materials), len(self.objects))\r
339 \r
340     def getline(self):\r
341         line=self.io.readline()\r
342         self.lines+=1\r
343         if line=="":\r
344             self.eof=True\r
345             return None\r
346         return line.strip()\r
347 \r
348     def printError(self, method, msg):\r
349         print("%s:%s:%d" % (method, msg, self.lines))\r
350 \r
351     @withio\r
352     def read(self):\r
353         line=self.getline()\r
354         if line!="Metasequoia Document":\r
355             print("invalid signature")\r
356             return False\r
357 \r
358         line=self.getline()\r
359         if line!="Format Text Ver 1.0":\r
360             print("unknown version: %s" % line)\r
361 \r
362         while True:\r
363             line=self.getline()\r
364             if line==None:\r
365                 # eof\r
366                 break;\r
367             if line=="":\r
368                 # empty line\r
369                 continue\r
370 \r
371             tokens=line.split()\r
372             key=tokens[0]\r
373 \r
374             if key=="Eof":\r
375                 return True\r
376             elif key=="Scene":\r
377                 if not self.readChunk():\r
378                     return False\r
379             elif key=="Material":\r
380                 if not self.readMaterial():\r
381                     return False\r
382             elif key=="Object":\r
383                 firstQuote=line.find('"')\r
384                 secondQuote=line.find('"', firstQuote+1)\r
385                 if not self.readObject(line[firstQuote+1:secondQuote]):\r
386                     return False\r
387             elif key=="BackImage":\r
388                 if not self.readChunk():\r
389                     return False\r
390             elif key=="IncludeXml":\r
391                 firstQuote=line.find('"')\r
392                 secondQuote=line.find('"', firstQuote+1)\r
393                 print("IncludeXml", line[firstQuote+1:secondQuote])\r
394             else:\r
395                 print("unknown key: %s" % key)\r
396                 if not self.readChunk():\r
397                     return False\r
398 \r
399         self.printError("parse", "invalid eof")\r
400         return False\r
401 \r
402     def readObject(self, name):\r
403         obj=Obj(name)\r
404         if name.startswith('bone'):\r
405             self.has_mikoto=True\r
406         self.objects.append(obj)\r
407         while(True):\r
408             line=self.getline()\r
409             if line==None:\r
410                 # eof\r
411                 break;\r
412             if line=="":\r
413                 # empty line\r
414                 continue\r
415 \r
416             if line=="}":\r
417                 return True\r
418             else:\r
419                 tokens=line.split()\r
420                 key=tokens[0]\r
421                 if key=="vertex":\r
422                     if not self.readVertex(obj):\r
423                         return False\r
424                 elif key=="face":\r
425                     if not self.readFace(obj):\r
426                         return False\r
427                 elif key=="depth":\r
428                     obj.depth=int(tokens[1])\r
429                 else:\r
430                     print(\r
431                             "%s#readObject" % name,\r
432                             "unknown key: %s" % key\r
433                             )\r
434 \r
435         self.printError("readObject", "invalid eof")\r
436         return False\r
437 \r
438     def readFace(self, obj):\r
439         while(True):\r
440             line=self.getline()\r
441             if line==None:\r
442                 # eof\r
443                 break;\r
444             if line=="":\r
445                 # empty line\r
446                 continue\r
447 \r
448             if line=="}":\r
449                 return True\r
450             else:\r
451                 # face\r
452                 tokens=line.split(' ', 1)\r
453                 try:\r
454                     obj.addFace(Face(int(tokens[0]), tokens[1]))\r
455                 except ValueError as ex:\r
456                     self.printError("readFace", ex)\r
457                     #return False\r
458 \r
459         self.printError("readFace", "invalid eof")\r
460         return False\r
461 \r
462     def readVertex(self, obj):\r
463         while(True):\r
464             line=self.getline()\r
465             if line==None:\r
466                 # eof\r
467                 break;\r
468             if line=="":\r
469                 # empty line\r
470                 continue\r
471 \r
472             if line=="}":\r
473                 return True\r
474             else:\r
475                 # vertex\r
476                 obj.addVertex(*[float(v) for v in line.split()])\r
477 \r
478         self.printError("readVertex", "invalid eof")\r
479         return False\r
480 \r
481     def readMaterial(self):\r
482         while(True):\r
483             line=self.getline()\r
484             if line==None:\r
485                 # eof\r
486                 break;\r
487             if line=="":\r
488                 # empty line\r
489                 continue\r
490 \r
491             if line=="}":\r
492                 return True\r
493             else:\r
494                 # material\r
495                 secondQuaote=line.find('"', 1)                \r
496                 material=Material(line[1:secondQuaote])\r
497                 try:\r
498                     material.parse(line[secondQuaote+2:])\r
499                 except ValueError as ex:\r
500                     self.printError("readMaterial", ex)\r
501 \r
502                 self.materials.append(material)\r
503 \r
504         self.printError("readMaterial", "invalid eof")\r
505         return False\r
506 \r
507     def readChunk(self):\r
508         level=1\r
509         while(True):\r
510             line=self.getline()\r
511             if line==None:\r
512                 # eof\r
513                 break;\r
514             if line=="":\r
515                 # empty line\r
516                 continue\r
517 \r
518             if line=="}":\r
519                 level-=1\r
520                 if level==0:\r
521                     return True\r
522             elif line.find("{")!=-1:\r
523                 level+=1\r
524 \r
525         self.printError("readChunk", "invalid eof")\r
526         return False\r
527 \r