OSDN Git Service

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