OSDN Git Service

d83433ef46c57141f74b07cbe2e170b4a31c62be
[meshio/meshio.git] / swig / blender / mqo_import.py
1 #!BPY\r
2 # coding: utf-8\r
3 """ \r
4 Name: 'Metasequoia(.mqo)...'\r
5 Blender: 245\r
6 Group: 'Import'\r
7 Tooltip: 'Import from Metasequoia file format (.mqo)'\r
8 """\r
9 __author__=['ousttrue']\r
10 __url__ = ["http://gunload.web.fc2.com/blender/"]\r
11 __version__= '0.6 2010/05/05'\r
12 __bpydoc__= '''\\r
13 \r
14 MQO Importer\r
15 \r
16 This script imports a mqo into Blender for editing.\r
17 \r
18 0.2 20080123: update.\r
19 0.3 20091125: modify for linux.\r
20 0.4 20100310: rewrite.\r
21 0.5 20100311: create armature from mikoto bone.\r
22 0.6 20100505: C extension.\r
23 0.7 20100606: integrate 2.4 and 2.5.\r
24 '''\r
25 ###############################################################################\r
26 # import\r
27 ###############################################################################\r
28 import os\r
29 import sys\r
30 import math\r
31 \r
32 # C extension\r
33 from meshio import mqo\r
34 \r
35 def isBlender24():\r
36     return sys.version_info[0]<3\r
37 \r
38 if isBlender24():\r
39     # for 2.4\r
40     import Blender\r
41     from Blender import Mathutils\r
42     import bpy\r
43 \r
44     # wrapper\r
45     import bl24 as bl\r
46 \r
47     # ファイルシステムの文字コード\r
48     # 改造版との共用のため\r
49     FS_ENCODING=sys.getfilesystemencoding()\r
50     if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):\r
51         INTERNAL_ENCODING='utf-8'\r
52     else:\r
53         INTERNAL_ENCODING=FS_ENCODING\r
54 else:\r
55     # for 2.5\r
56     import bpy\r
57     from bpy.props import *\r
58 \r
59     # wrapper\r
60     import bl25 as bl\r
61 \r
62 \r
63 ###############################################################################\r
64 # implement\r
65 ###############################################################################\r
66 def has_mikoto(mqo):\r
67     return False\r
68 \r
69 if isBlender24():\r
70     def create_materials(scene, mqo, directory):\r
71         """\r
72         create blender materials and renturn material list.\r
73         """\r
74         materials = []\r
75         images = []\r
76         for m in mqo.materials:\r
77             material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))\r
78             materials.append(material)\r
79 \r
80             material.mode |= Blender.Material.Modes.SHADELESS\r
81             material.rgbCol = [m.color.r, m.color.g, m.color.b]\r
82             material.alpha = m.color.a\r
83             material.amb = m.ambient\r
84             material.spec = m.specular\r
85             material.hard = int(255 * m.power)\r
86             if m.texture!="":\r
87                 texture_path=m.getTexture()\r
88 \r
89                 # load texture image\r
90                 if os.path.isabs(texture_path):\r
91                     # absolute\r
92                     path = texture_path\r
93                 else:\r
94                     # relative\r
95                     path = os.path.join(directory, texture_path)\r
96 \r
97                 # backslash to slash\r
98                 #path = path.replace('\\', '/')\r
99 \r
100                 # texture\r
101                 if os.path.exists(path):\r
102                     image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))\r
103                     images.append(image)\r
104                     material.mode = material.mode | Blender.Material.Modes.TEXFACE\r
105                     tex = Blender.Texture.New(path.encode(INTERNAL_ENCODING))\r
106                     tex.type = Blender.Texture.Types.IMAGE\r
107                     tex.image = image\r
108                     material.setTexture(0, tex, Blender.Texture.TexCo.UV)\r
109                 else:\r
110                     print("%s not exits" % path)\r
111                 \r
112         return materials, {}\r
113 \r
114 \r
115     def create_objects(scene, mqo, root, materials, imageMap=None, scale=None):\r
116         """\r
117         create blender mesh objects.\r
118         """\r
119         # store hierarchy\r
120         stack=[root]    \r
121 \r
122         objects=[]\r
123         for o in mqo.objects:\r
124             #print "%s:v(%d),f(%d)" % (o.name, len(o.vertices), len(o.faces))\r
125             # create mesh\r
126             mesh = Blender.Mesh.New()\r
127             mesh_object=scene.objects.new(mesh, o.name.encode('utf-8'))\r
128 \r
129             # add hierarchy\r
130             stack_depth=len(stack)-1\r
131             print(o.depth, stack_depth)\r
132             if o.depth<stack_depth:\r
133                 for i in range(stack_depth-o.depth):\r
134                     stack.pop()\r
135             stack[-1].makeParent([mesh_object])\r
136             stack.append(mesh_object)\r
137 \r
138             if o.name.startswith('sdef'):\r
139                 # add sdef object\r
140                 objects.append(mesh_object)\r
141             elif o.name.startswith('anchor'):\r
142                 #print("hide %s" % o.name)\r
143                 #mesh_object.restrictDisplay=False\r
144                 mesh_object.layers=[2]\r
145             elif o.name.startswith('bone'):\r
146                 mesh_object.layers=[2]\r
147 \r
148             # add vertices\r
149             mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy\r
150             mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])\r
151             # add faces\r
152             mesh_faces=[]\r
153             for face in o.faces:\r
154                 face_indices=[]\r
155                 for i in xrange(face.index_count):\r
156                     face_indices.append(face.getIndex(i)+1)\r
157                 mesh_faces.append(face_indices)\r
158             #new_faces=mesh.faces.extend([face.indices for face in o.faces], \r
159             new_faces=mesh.faces.extend(mesh_faces,\r
160                     #ignoreDups=True, \r
161                     indexList=True)\r
162             mesh.update()\r
163             \r
164             # gather used materials\r
165             usedMaterials = {}\r
166             if new_faces:\r
167                 for i in new_faces:\r
168                     if type(i) is int:\r
169                         usedMaterials[o.faces[i].material_index]=True\r
170 \r
171             # blender limits 16 materials per mesh\r
172             # separate mesh ?\r
173             for i, material_index in enumerate(usedMaterials.keys()):\r
174                 if i>=16:\r
175                     print("over 16 materials!")\r
176                     break\r
177                 mesh.materials+=[materials[material_index]]\r
178                 usedMaterials[material_index]=i\r
179             \r
180             # set face params\r
181             for i, f in enumerate(o.faces):       \r
182                 if not type(new_faces[i]) is int:\r
183                     continue\r
184 \r
185                 face=mesh.faces[new_faces[i]]\r
186 \r
187                 uv_array=[]\r
188                 for i in xrange(f.index_count):\r
189                     uv_array.append(Blender.Mathutils.Vector(\r
190                         f.getUV(i).x, \r
191                         1.0-f.getUV(i).y)\r
192                         )\r
193                 try:\r
194                     face.uv=uv_array\r
195                 except Exception as msg:\r
196                     #print msg\r
197                     #print face.index, uv_array\r
198                     pass\r
199             \r
200                 if f.material_index in usedMaterials:\r
201                     face.mat = usedMaterials[f.material_index]\r
202 \r
203                 face.smooth = 1\r
204 \r
205             # rmeove dummy 0 vertex\r
206             mesh.verts.delete(0)\r
207                 \r
208             mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH\r
209             mesh.maxSmoothAngle = int(o.smoothing)\r
210             mesh.smooth()\r
211             mesh.calcNormals()\r
212             mesh.flipNormals()\r
213             mesh.update()\r
214 \r
215             # mirror modifier\r
216             if o.mirror:\r
217                 mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)\r
218 \r
219         return objects\r
220 \r
221 \r
222     class MikotoBone(object):\r
223         __slots__=[\r
224                 'name',\r
225                 'iHead', 'iTail', 'iUp',\r
226                 'vHead', 'vTail', 'vUp',\r
227                 'parent', 'isFloating',\r
228                 'children',\r
229                 ]\r
230         def __init__(self, face=None, vertices=None, materials=None):\r
231             self.parent=None\r
232             self.isFloating=False\r
233             self.children=[]\r
234             if not face:\r
235                 self.name='root'\r
236                 return\r
237 \r
238             self.name=materials[face.material_index].name.encode('utf-8')\r
239 \r
240             i0=face.indices[0]\r
241             i1=face.indices[1]\r
242             i2=face.indices[2]\r
243             v0=vertices[i0]\r
244             v1=vertices[i1]\r
245             v2=vertices[i2]\r
246             e01=v1-v0\r
247             e12=v2-v1\r
248             e20=v0-v2\r
249             sqNorm0=e01.getSqNorm()\r
250             sqNorm1=e12.getSqNorm()\r
251             sqNorm2=e20.getSqNorm()\r
252             if sqNorm0>sqNorm1:\r
253                 if sqNorm1>sqNorm2:\r
254                     # e01 > e12 > e20\r
255                     self.iHead=i2\r
256                     self.iTail=i1\r
257                     self.iUp=i0\r
258                 else:\r
259                     if sqNorm0>sqNorm2:\r
260                         # e01 > e20 > e12\r
261                         self.iHead=i2\r
262                         self.iTail=i0\r
263                         self.iUp=i1\r
264                     else:\r
265                         # e20 > e01 > e12\r
266                         self.iHead=i1\r
267                         self.iTail=i0\r
268                         self.iUp=i2\r
269             else:\r
270                 # 0 < 1\r
271                 if sqNorm1<sqNorm2:\r
272                     # e20 > e12 > e01\r
273                     self.iHead=i1\r
274                     self.iTail=i2\r
275                     self.iUp=i0\r
276                 else:\r
277                     if sqNorm0<sqNorm2:\r
278                         # e12 > e20 > e01\r
279                         self.iHead=i0\r
280                         self.iTail=i2\r
281                         self.iUp=i1\r
282                     else:\r
283                         # e12 > e01 > e20\r
284                         self.iHead=i0\r
285                         self.iTail=i1\r
286                         self.iUp=i2\r
287             self.vHead=vertices[self.iHead]\r
288             self.vTail=vertices[self.iTail]\r
289             self.vUp=vertices[self.iUp]\r
290 \r
291             if self.name.endswith('[]'):\r
292                 basename=self.name[0:-2]\r
293                 # expand LR name\r
294                 if self.vTail.x>0:\r
295                     self.name="%s_L" % basename\r
296                 else:\r
297                     self.name="%s_R" % basename\r
298 \r
299 \r
300         def setParent(self, parent, floating=False):\r
301             if floating:\r
302                 self.isFloating=True\r
303             self.parent=parent\r
304             parent.children.append(self)\r
305 \r
306         def printTree(self, indent=''):\r
307             print("%s%s" % (indent, self.name))\r
308             for child in self.children:\r
309                 child.printTree(indent+'  ')\r
310 \r
311 \r
312     def build_armature(armature, mikotoBone, parent=None):\r
313         """\r
314         create a armature bone.\r
315         """\r
316         bone = Armature.Editbone()\r
317         bone.name = mikotoBone.name.encode('utf-8')\r
318         armature.bones[bone.name] = bone\r
319 \r
320         bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())\r
321         bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())\r
322         if parent:\r
323             bone.parent=parent\r
324             if mikotoBone.isFloating:\r
325                 pass\r
326             else:\r
327                 bone.options=[Armature.CONNECTED]\r
328 \r
329         for child in mikotoBone.children:\r
330             build_armature(armature, child, bone)\r
331 \r
332 \r
333     def create_armature(scene, mqo):\r
334         """\r
335         create armature\r
336         """\r
337         boneObject=None\r
338         for o in mqo.objects:\r
339             if o.name.startswith('bone'):\r
340                 boneObject=o\r
341                 break\r
342         if not boneObject:\r
343             return\r
344 \r
345         tailMap={}\r
346         for f in boneObject.faces:\r
347             if f.index_count!=3:\r
348                 print("invalid index_count: %d" % f.index_count)\r
349                 continue\r
350             b=MikotoBone(f, boneObject.vertices, mqo.materials)\r
351             tailMap[b.iTail]=b\r
352 \r
353         #################### \r
354         # build mikoto bone tree\r
355         #################### \r
356         mikotoRoot=MikotoBone()\r
357 \r
358         for b in tailMap.values():\r
359             # each bone has unique parent or is root bone.\r
360             if b.iHead in tailMap:\r
361                 b.setParent(tailMap[b.iHead])\r
362             else: \r
363                 isFloating=False\r
364                 for e in boneObject.edges:\r
365                     if  b.iHead==e.indices[0]:\r
366                         # floating bone\r
367                         if e.indices[1] in tailMap:\r
368                             b.setParent(tailMap[e.indices[1]], True)\r
369                             isFloating=True\r
370                             break\r
371                     elif b.iHead==e.indices[1]:\r
372                         # floating bone\r
373                         if e.indices[0] in tailMap:\r
374                             b.setParent(tailMap[e.indices[0]], True)\r
375                             isFloating=True\r
376                             break\r
377                 if isFloating:\r
378                     continue\r
379 \r
380                 # no parent bone\r
381                 b.setParent(mikotoRoot, True)\r
382 \r
383         if len(mikotoRoot.children)==0:\r
384             print("no root bone")\r
385             return\r
386 \r
387         if len(mikotoRoot.children)==1:\r
388             # single root\r
389             mikotoRoot=mikotoRoot.children[0]\r
390             mikotoRoot.parent=None\r
391         else:\r
392             mikotoRoot.vHead=Vector3(0, 10, 0)\r
393             mikotoRoot.vTail=Vector3(0, 0, 0)\r
394 \r
395         #################### \r
396         # create armature\r
397         #################### \r
398         armature = Armature.New()\r
399         # link to object\r
400         armature_object = scene.objects.new(armature)\r
401         # create action\r
402         act = Armature.NLA.NewAction()\r
403         act.setActive(armature_object)\r
404         # set XRAY\r
405         armature_object.drawMode |= Object.DrawModes.XRAY\r
406         # armature settings\r
407         armature.drawType = Armature.OCTAHEDRON\r
408         armature.envelopes = False\r
409         armature.vertexGroups = True\r
410         armature.mirrorEdit = True\r
411         armature.drawNames=True\r
412 \r
413         # edit bones\r
414         armature.makeEditable()\r
415         build_armature(armature, mikotoRoot)\r
416         armature.update()\r
417 \r
418         return armature_object\r
419             \r
420 \r
421     class TrianglePlane(object):\r
422         """\r
423         mikoto方式ボーンのアンカーウェイト計算用。\r
424         (不完全)\r
425         """\r
426         __slots__=['normal', \r
427                 'v0', 'v1', 'v2',\r
428                 ]\r
429         def __init__(self, v0, v1, v2):\r
430             self.v0=v0\r
431             self.v1=v1\r
432             self.v2=v2\r
433 \r
434         def isInsideXY(self, p):\r
435             v0=Vector2(self.v0.x, self.v0.y)\r
436             v1=Vector2(self.v1.x, self.v1.y)\r
437             v2=Vector2(self.v2.x, self.v2.y)\r
438             e01=v1-v0\r
439             e12=v2-v1\r
440             e20=v0-v2\r
441             c0=Vector2.cross(e01, p-v0)\r
442             c1=Vector2.cross(e12, p-v1)\r
443             c2=Vector2.cross(e20, p-v2)\r
444             if c0>=0 and c1>=0 and c2>=0:\r
445                 return True\r
446             if c0<=0 and c1<=0 and c2<=0:\r
447                 return True\r
448 \r
449         def isInsideYZ(self, p):\r
450             v0=Vector2(self.v0.y, self.v0.z)\r
451             v1=Vector2(self.v1.y, self.v1.z)\r
452             v2=Vector2(self.v2.y, self.v2.z)\r
453             e01=v1-v0\r
454             e12=v2-v1\r
455             e20=v0-v2\r
456             c0=Vector2.cross(e01, p-v0)\r
457             c1=Vector2.cross(e12, p-v1)\r
458             c2=Vector2.cross(e20, p-v2)\r
459             if c0>=0 and c1>=0 and c2>=0:\r
460                 return True\r
461             if c0<=0 and c1<=0 and c2<=0:\r
462                 return True\r
463 \r
464         def isInsideZX(self, p):\r
465             v0=Vector2(self.v0.z, self.v0.x)\r
466             v1=Vector2(self.v1.z, self.v1.x)\r
467             v2=Vector2(self.v2.z, self.v2.x)\r
468             e01=v1-v0\r
469             e12=v2-v1\r
470             e20=v0-v2\r
471             c0=Vector2.cross(e01, p-v0)\r
472             c1=Vector2.cross(e12, p-v1)\r
473             c2=Vector2.cross(e20, p-v2)\r
474             if c0>=0 and c1>=0 and c2>=0:\r
475                 return True\r
476             if c0<=0 and c1<=0 and c2<=0:\r
477                 return True\r
478 \r
479 \r
480     class MikotoAnchor(object):\r
481         """\r
482         mikoto方式スケルトンのアンカー。\r
483         """\r
484         __slots__=[\r
485                 "triangles", "bbox",\r
486                 ]\r
487         def __init__(self):\r
488             self.triangles=[]\r
489             self.bbox=None\r
490 \r
491         def push(self, face, vertices):\r
492             if face.index_count==3:\r
493                 self.triangles.append(TrianglePlane(\r
494                     vertices[face.indices[0]],\r
495                     vertices[face.indices[1]],\r
496                     vertices[face.indices[2]]\r
497                     ))\r
498             elif face.index_count==4:\r
499                 self.triangles.append(TrianglePlane(\r
500                     vertices[face.indices[0]],\r
501                     vertices[face.indices[1]],\r
502                     vertices[face.indices[2]]\r
503                     ))\r
504                 self.triangles.append(TrianglePlane(\r
505                     vertices[face.indices[2]],\r
506                     vertices[face.indices[3]],\r
507                     vertices[face.indices[0]]\r
508                     ))\r
509             # bounding box\r
510             if not self.bbox:\r
511                 self.bbox=BoundingBox(vertices[face.indices[0]])\r
512             for i in face.indices:\r
513                 self.bbox.expand(vertices[i])\r
514 \r
515 \r
516         def calcWeight(self, v):\r
517             if not self.bbox.isInside(v):\r
518                 return 0\r
519 \r
520             if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):\r
521                 return 1.0\r
522             else:\r
523                 return 0\r
524             \r
525         def anyXY(self, x, y):\r
526             for t in self.triangles:\r
527                 if t.isInsideXY(Vector2(x, y)):\r
528                     return True\r
529             return False\r
530 \r
531         def anyYZ(self, y, z):\r
532             for t in self.triangles:\r
533                 if t.isInsideYZ(Vector2(y, z)):\r
534                     return True\r
535             return False\r
536 \r
537         def anyZX(self, z, x):\r
538             for t in self.triangles:\r
539                 if t.isInsideZX(Vector2(z, x)):\r
540                     return True\r
541             return False\r
542 \r
543 \r
544     def create_bone_weight(scene, mqo, armature_object, objects):\r
545         """\r
546         create mikoto bone weight.\r
547         """\r
548         anchorMap={}\r
549         # setup mikoto anchors\r
550         for o in mqo.objects:\r
551             if o.name.startswith("anchor"):\r
552                 for f in o.faces:\r
553                     name=mqo.materials[f.material_index].name\r
554                     if name.endswith('[]'):\r
555                         basename=name[0:-2]\r
556                         v=o.vertices[f.indices[0]]\r
557                         if(v.x>0):\r
558                             # L\r
559                             name_L=basename+'_L'\r
560                             if not name_L in anchorMap:\r
561                                 anchorMap[name_L]=MikotoAnchor()\r
562                             anchorMap[name_L].push(f, o.vertices)\r
563                         elif(v.x<0):\r
564                             # R\r
565                             name_R=basename+'_R'\r
566                             if not name_R in anchorMap:\r
567                                 anchorMap[name_R]=MikotoAnchor()\r
568                             anchorMap[name_R].push(f, o.vertices)\r
569                         else:\r
570                             print("no side", v)\r
571                     else:\r
572                         if not name in anchorMap:\r
573                             anchorMap[name]=MikotoAnchor()\r
574                         anchorMap[name].push(f, o.vertices)\r
575 \r
576         for o in objects:\r
577             # add armature modifier\r
578             mod=o.modifiers.append(Modifier.Types.ARMATURE)\r
579             mod[Modifier.Settings.OBJECT] = armature_object\r
580             mod[Modifier.Settings.ENVELOPES] = False\r
581             o.makeDisplayList()\r
582             # create vertex group\r
583             mesh=o.getData(mesh=True)\r
584             for name in anchorMap.keys():\r
585                 mesh.addVertGroup(name)\r
586             mesh.update()\r
587                      \r
588         # assing vertices to vertex group\r
589         for o in objects:\r
590             mesh=o.getData(mesh=True)\r
591             for i, mvert in enumerate(mesh.verts):\r
592                 hasWeight=False\r
593                 for name, anchor in anchorMap.items():\r
594                     weight=anchor.calcWeight(mvert.co)\r
595                     if weight>0:\r
596                         mesh.assignVertsToGroup(\r
597                                 name, [i], weight, Mesh.AssignModes.ADD)\r
598                         hasWeight=True\r
599                 if not hasWeight:\r
600                     # debug orphan vertex\r
601                     print('orphan', mvert)\r
602             mesh.update()\r
603         \r
604 \r
605 \r
606 else:\r
607     def create_texture(directory, texture_name):\r
608         texture=bpy.data.textures.new(texture_name)\r
609         texture.type='IMAGE'\r
610         texture=texture.recast_type()\r
611         #texturePath="%s/%s" % (directory, texture_name)\r
612         texturePath=os.path.join(directory, texture_name)\r
613         print('create_texture', texturePath)\r
614         image=bpy.data.images.load(texturePath)\r
615         texture.image=image\r
616         texture.mipmap = True\r
617         texture.interpolation = True\r
618         texture.use_alpha = True\r
619         return texture\r
620 \r
621     def create_materials(scene, mqo, directory):\r
622         materials = []\r
623         textureMap={}\r
624         imageMap={}\r
625         if len(mqo.materials)>0:\r
626             for material_index, m in enumerate(mqo.materials):\r
627                 material = bpy.data.materials.new(m.getName())\r
628                 materials.append(material)\r
629                 # mqo material\r
630                 material.diffuse_color=[m.color.r, m.color.g, m.color.b]\r
631                 material.alpha=m.color.a\r
632                 material.diffuse_intensity=m.diffuse\r
633                 texture_name=m.getTexture()\r
634                 if texture_name!='':\r
635                     if texture_name in textureMap:\r
636                         texture=textureMap[texture_name]\r
637                     else:\r
638                         texture=create_texture(directory, texture_name)\r
639                         textureMap[texture_name]=texture\r
640                         imageMap[material_index]=texture.image\r
641                     #material.add_texture(texture, "UV", {"COLOR", "ALPHA"})\r
642                     material.add_texture(texture, "UV", "COLOR")\r
643                     # temporary\r
644                     material.emit=1.0\r
645         else:\r
646             material = bpy.data.materials.new('Default')\r
647             materials.append(material)\r
648         return materials, imageMap\r
649 \r
650     def create_objects(scene, mqo, parent, materials, imageMap, scale):\r
651         for o in mqo.objects:\r
652 \r
653             # create mesh\r
654             mesh=bpy.data.meshes.new("Mesh")\r
655             meshObject= bpy.data.objects.new(o.getName(), mesh)\r
656             scene.objects.link(meshObject)\r
657             meshObject.parent=parent\r
658 \r
659             # count triangle and quadrangle\r
660             faceCount=0\r
661             for f in o.faces:\r
662                 if f.index_count==3 or f.index_count==4:\r
663                     faceCount+=1\r
664             mesh.add_geometry(len(o.vertices), 0, faceCount)\r
665 \r
666             # add vertex\r
667             unpackedVertices=[]\r
668             for v in o.vertices:\r
669                 # convert right-handed y-up to right-handed z-up\r
670                 unpackedVertices.extend(\r
671                         (scale*v.x, scale*-v.z, scale*v.y))\r
672             mesh.verts.foreach_set("co", unpackedVertices)\r
673 \r
674             # add face\r
675             unpackedFaces = []\r
676             usedMaterial=set()\r
677 \r
678             def getFace(f):\r
679                 face = []\r
680                 for i in range(f.index_count):\r
681                     face.append(f.getIndex(i))\r
682                 return face\r
683 \r
684             for f in o.faces:\r
685                 face=getFace(f)\r
686                 if len(face) != 3 and len(face) != 4:\r
687                     print("{0} vertices in face.".format(len(face)))\r
688                     continue\r
689 \r
690                 if len(face) == 4:\r
691                     if face[3] == 0:\r
692                         # rotate indices if the 4th is 0\r
693                         face = [face[3], face[0], face[1], face[2]]\r
694                 elif len(face) == 3:\r
695                     if face[2] == 0:\r
696                         # rotate indices if the 3rd is 0\r
697                         face = [face[2], face[0], face[1], 0]\r
698                     else:\r
699                         face.append(0)\r
700 \r
701                 unpackedFaces.extend(face)\r
702                 usedMaterial.add(f.material_index)\r
703             try:\r
704                 mesh.faces.foreach_set("verts_raw", unpackedFaces)\r
705             except:\r
706                 #print([getFace(f) for f in o.faces])\r
707                 print("fail to mesh.faces.foreach_set")\r
708                 return\r
709 \r
710             # add material\r
711             meshMaterialMap={}\r
712             materialIndex=0\r
713             for i in usedMaterial:\r
714                 mesh.add_material(materials[i])\r
715                 meshMaterialMap[i]=materialIndex\r
716                 materialIndex+=1\r
717 \r
718             # each face\r
719             mesh.add_uv_texture()\r
720             for mqo_face, blender_face, uv_face in zip(\r
721                     o.faces, mesh.faces, mesh.uv_textures[0].data):\r
722                 if mqo_face.index_count<3:\r
723                     continue\r
724                 blender_face.material_index=meshMaterialMap[mqo_face.material_index]\r
725                 if mqo_face.index_count>=3:\r
726                     uv_face.uv1=[mqo_face.getUV(0).x, 1.0-mqo_face.getUV(0).y]\r
727                     uv_face.uv2=[mqo_face.getUV(1).x, 1.0-mqo_face.getUV(1).y]\r
728                     uv_face.uv3=[mqo_face.getUV(2).x, 1.0-mqo_face.getUV(2).y]\r
729                     if mqo_face.index_count==4:\r
730                         uv_face.uv4=[\r
731                                 mqo_face.getUV(3).x, 1.0-mqo_face.getUV(3).y]\r
732                 if materials[mqo_face.material_index] in imageMap:\r
733                     uv_face.image=imageMap[mqo_face.material_index]\r
734                     uv_face.tex=True\r
735 \r
736             mesh.update()\r
737 \r
738 \r
739 def __execute(filename, scene, scale=1.0):\r
740     # parse file\r
741     io=mqo.IO()\r
742     if not io.read(filename):\r
743         print("fail to load",filename)\r
744         return\r
745 \r
746     # create materials\r
747     materials, imageMap=create_materials(scene, io, os.path.dirname(filename))\r
748 \r
749     # create objects\r
750     root=bl.createEmptyObject(scene, os.path.basename(filename))\r
751     objects=create_objects(scene, io, root, materials, imageMap, scale)\r
752 \r
753     if has_mikoto(io):\r
754         # create mikoto bone\r
755         armature_object=create_armature(scene, io)\r
756         if armature_object:\r
757             root.makeParent([armature_object])\r
758 \r
759             # create bone weight\r
760             create_bone_weight(scene, io, armature_object, objects)\r
761 \r
762  \r
763 ###############################################################################\r
764 # register\r
765 ###############################################################################\r
766 if isBlender24():\r
767     def execute_24(filename):\r
768         """\r
769         import a mqo file.\r
770         """\r
771         filename=filename.decode(INTERNAL_ENCODING)\r
772         print("##start mqo_import.py##")\r
773         print(INTERNAL_ENCODING, FS_ENCODING)\r
774         print("parse mqo file: %s" % (filename))\r
775 \r
776         Blender.Window.WaitCursor(1) \r
777         t = Blender.sys.time() \r
778 \r
779         # execute\r
780         scene = Blender.Scene.GetCurrent()\r
781         __execute(filename, scene)\r
782         scene.update(0)\r
783 \r
784         print('finished in %.2f seconds' % (Blender.sys.time()-t))\r
785         print('')\r
786         Blender.Redraw()\r
787         Blender.Window.WaitCursor(0) \r
788 \r
789     # for 2.4\r
790     # execute\r
791     Blender.Window.FileSelector(execute_24, 'Import MQO', '*.mqo')\r
792 else:\r
793     def execute_25(filename, context, scale):\r
794         """\r
795         import a mqo file.\r
796         """\r
797         __execute(filename, context.scene, scale)\r
798 \r
799     # for 2.5\r
800     # import operator\r
801     class IMPORT_OT_mqo(bpy.types.Operator):\r
802         '''Import from Metasequoia file format (.mqo)'''\r
803         bl_idname = "import_scene.mqo"\r
804         bl_label = 'Import MQO'\r
805 \r
806         # List of operator properties, the attributes will be assigned\r
807         # to the class instance from the operator settings before calling.\r
808 \r
809         path = StringProperty(\r
810                 name="File Path", \r
811                 description="File path used for importing the MQO file", \r
812                 maxlen= 1024, default= "")\r
813         filename = StringProperty(\r
814                 name="File Name", \r
815                 description="Name of the file.")\r
816         directory = StringProperty(\r
817                 name="Directory", \r
818                 description="Directory of the file.")\r
819 \r
820         scale = FloatProperty(\r
821                 name="Scale", \r
822                 description="Scale the MQO by this value", \r
823                 min=0.0001, max=1000000.0, \r
824                 soft_min=0.001, soft_max=100.0, default=1.0)\r
825 \r
826         def execute(self, context):\r
827             execute_25(self.properties.path, context, self.properties.scale)\r
828             return 'FINISHED'\r
829 \r
830         def invoke(self, context, event):\r
831             wm=context.manager\r
832             wm.add_fileselect(self)\r
833             return 'RUNNING_MODAL'\r
834 \r
835 \r
836     # register menu\r
837     def menu_func(self, context): \r
838         self.layout.operator(IMPORT_OT_mqo.bl_idname, \r
839                 text="Metasequoia (.mqo)")\r
840 \r
841     def register():\r
842         bpy.types.register(IMPORT_OT_mqo)\r
843         bpy.types.INFO_MT_file_import.append(menu_func)\r
844 \r
845     def unregister():\r
846         bpy.types.unregister(IMPORT_OT_mqo)\r
847         bpy.types.INFO_MT_file_import.remove(menu_func)\r
848 \r
849     if __name__=="__main__":\r
850         register()\r
851 \r