OSDN Git Service

aefdc4bca788497d3d15bae2ae80d240a9da282e
[meshio/meshio.git] / swig / blender / pmd_import.py
1 #!BPY
2 # coding:utf-8
3 """
4  Name: 'MikuMikuDance model (.pmd)...'
5  Blender: 248
6  Group: 'Import'
7  Tooltip: 'Import PMD file for MikuMikuDance.'
8 """
9 __author__= ["ousttrue"]
10 __version__= "1.1"
11 __url__=()
12 __bpydoc__="""
13 pmd Importer
14
15 This script imports a pmd into Blender for editing.
16
17 0.1: 20091126: first implement.
18 0.2: 20091209: implement IK.
19 0.3: 20091210: implement morph target.
20 0.4: 20100305: use english name.
21 0.5: 20100408: cleanup not used vertices.
22 0.6: 20100416: fix fornt face. texture load fail safe. add progress.
23 0.7: 20100506: C extension.
24 0.8: 20100521: add shape_key group.
25 1.0: 20100530: add invisilbe bone tail(armature layer 2).
26 1.1: 20100608: integrate 2.4 and 2.5.
27 """
28
29 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
30
31
32 ###############################################################################
33 # import
34 ###############################################################################
35 import os
36 import sys
37 import re
38 import math
39
40 # C extension
41 from meshio import pmd, englishmap
42
43 def isBlender24():
44     return sys.version_info[0]<3
45
46 if isBlender24():
47     # for 2.4
48     import Blender
49     from Blender import Mathutils
50     import bpy
51
52     # wrapper
53     import bl24 as bl
54 else:
55     # for 2.5
56     import bpy
57     from bpy.props import *
58     import mathutils
59
60     # wrapper
61     import bl25 as bl
62
63     xrange=range
64
65 ###############################################################################
66 # progress bar
67 ###############################################################################
68 def progress_start(base):
69     global progressBar
70     progressBar=bl.ProgressBar(base)
71
72 def progress_finish():
73     global progressBar
74     progressBar.finish()
75
76 def progress_print(message, progress=0.05):
77     global progressBar
78     progressBar.advance(message, progress)
79
80 def progress_set(message, progress):
81     global progressBar
82     progressBar.set(message, progress)
83
84
85 if isBlender24():
86     # functions
87     def convert_coord(pos):
88         """
89         Left handed y-up to Right handed z-up
90         """
91         return (pos.x, pos.z, pos.y)
92
93
94     def convert_uv(uv):
95         return (uv.x, 1.0 - uv.y)
96
97
98     def get_bone_name(l, index):
99         name=englishmap.getEnglishBoneName(l.bones[index].getName())
100         return name if name else l.bones[index].getName().encode(bl.INTERNAL_ENCODING)
101
102
103     class Builder(object):
104         def __init__(self):
105             self.boneMap={}
106
107         def build(self, armature, bones):
108             for b in bones:
109                 if not b.parent:
110                     self.__build(armature, b, None, None)
111             armature.update()
112
113         def __build(self, armature, b, p, parent):
114             name=englishmap.getEnglishBoneName(b.getName())
115             if not name:
116                 name=b.getName().encode(bl.INTERNAL_ENCODING)
117             self.boneMap[name]=b
118
119             bone=Blender.Armature.Editbone()
120             bone.name=name
121             armature.bones[name]=bone
122
123             if b.tail_index==0:
124                 # 先端
125                 assert(b.type==6 or b.type==7)
126                 bone.head = Mathutils.Vector(*convert_coord(b.pos))
127                 bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
128                 assert(parent)
129                 bone.parent=parent
130                 if bone.name=="center_t":
131                     # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
132                     parent.tail=parent.head+Mathutils.Vector(0, 1, 0)
133                     bone.head=parent.tail
134                     bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
135                 else:
136                     assert(parent.tail==bone.head)
137                 bone.options=[Blender.Armature.CONNECTED]
138                 # armature layer 2
139                 bone.layerMask = (1<<1)
140             else:
141                 bone.head = Mathutils.Vector(*convert_coord(b.pos))
142                 bone.tail = Mathutils.Vector(*convert_coord(b.tail))
143                 if parent:
144                     bone.parent=parent
145                     if parent.tail==bone.head:
146                         bone.options=[Blender.Armature.CONNECTED]
147
148             if bone.head==bone.tail:
149                 bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
150
151             for c in b.children:
152                 self.__build(armature, c, b, bone)
153
154
155     def importArmature(scene, l):
156         # create armature
157         armature = Blender.Armature.New()
158         # link to object
159         armature_object = scene.objects.new(armature)
160         # create action
161         act = Blender.Armature.NLA.NewAction()
162         act.setActive(armature_object)
163         # set XRAY
164         armature_object.drawMode = (
165                 armature_object.drawMode | Blender.Object.DrawModes.XRAY)
166         # armature settings
167         armature.drawType = Blender.Armature.OCTAHEDRON
168         armature.drawNames=True
169         armature.envelopes = False
170         armature.vertexGroups = True
171         armature.mirrorEdit = True
172
173         # create armature
174         armature.makeEditable()
175
176         ############################################################
177         # build bone
178         ############################################################
179         builder=Builder()
180         builder.build(armature, l.bones)
181
182         ############################################################
183         # IK
184         ############################################################
185         pose = armature_object.getPose()
186         cSetting = Blender.Constraint.Settings
187         for ik in l.ik_list:
188             # IKtarget->parent(=IK).name
189             target=l.bones[ik.target]
190             name = englishmap.getEnglishBoneName(target.getName())
191             p_bone = pose.bones[name]
192             if not p_bone:
193                 print('not found', name)
194                 continue
195             if len(ik.children) >= 16:
196                 print('over MAX_CHAINLEN', ik, len(ik.children))
197                 continue
198             # IK solver
199             ik_solver = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
200             ik_solver[cSetting.CHAINLEN]=len(ik.children)
201             ik_solver[cSetting.TARGET]=armature_object
202             ik_solver[cSetting.USETIP]=False
203
204             effector_name=englishmap.getEnglishBoneName(
205                     l.bones[ik.index].getName())
206             if not effector_name:
207                 effector_name=l.bones[ik.index].getName()
208
209             ik_solver[cSetting.BONE]=effector_name
210             #ik_solver.influence=ik.weight
211             # not used. place folder when export.
212             ik_solver[cSetting.ROTWEIGHT]=ik.weight
213             ik_solver[cSetting.ITERATIONS]=ik.iterations * 10
214
215         armature.makeEditable()
216         armature.update()
217
218         return armature_object
219         
220
221     def importShape(obj, l, vertex_map):
222         if len(l.morph_list)==0:
223             return
224         obj.pinShape=True
225         mesh=obj.getData(mesh=True)
226
227         # find base 
228         base=None
229         for s in l.morph_list:
230             if s.type==0:
231                 base=s
232
233                 # create vertex group
234                 mesh.addVertGroup(MMD_SHAPE_GROUP_NAME)
235                 indices=[]
236                 hasShape=False
237                 for i in s.indices:
238                     if i in vertex_map:
239                         hasShape=True
240                         indices.append(vertex_map[i])
241                 mesh.assignVertsToGroup(MMD_SHAPE_GROUP_NAME, indices, 0, 
242                         Blender.Mesh.AssignModes.ADD)
243                 if not hasShape:
244                     return
245
246                 # create base key
247                 mesh.insertKey()
248                 assert(len(mesh.key.blocks)==1)
249                 baseShapeIndex=0
250                 baseShapeBlock=mesh.key.blocks[baseShapeIndex]
251                 baseShapeBlock.name='Basis'
252                 obj.activeShape=baseShapeIndex
253                 mesh.update()
254                 break
255
256         assert(base)
257
258         # each skin
259         for s in l.morph_list:
260             if s.name==base.name:
261                 continue
262
263             for index, offset in zip(s.indices, s.pos_list):
264                 try:
265                     vertex_index=vertex_map[base.indices[index]]
266                     v=mesh.verts[vertex_index].co
267                     offset=convert_coord(offset)
268                     v[0]+=offset[0]
269                     v[1]+=offset[1]
270                     v[2]+=offset[2]
271                 except IndexErrora as msg:
272                     print(msg)
273                     print(index, len(base.indices), len(vertex_map))
274                     print(len(mesh.verts))
275                     print(base.indices[index])
276                     print(vertex_index)
277                     break
278                 except KeyError:
279                     #print 'this mesh not has shape vertices'
280                     break
281
282             # get skin name
283             name=englishmap.getEnglishSkinName(s.getName())
284             if not name:
285                 name=s.getName().encode(bl.INTERNAL_ENCODING)
286                 print(name)
287
288             # create shapekey block
289             mesh.insertKey()
290             shapeIndex=len(mesh.key.blocks)-1
291             keyBlock=mesh.key.blocks[shapeIndex]
292             keyBlock.name=name
293
294             # copy vertex to shape key
295             mesh.update()
296             
297             # restore
298             for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
299                 mv.co[0] = v[0]
300                 mv.co[1] = v[1]
301                 mv.co[2] = v[2]
302             mesh.update()
303
304         # select base shape
305         obj.activeShape=baseShapeIndex
306
307 else:
308     # for 2.5
309     def to_radian(degree):
310         return math.pi * degree / 180
311
312
313     def convert_coord(pos):
314         """
315         Left handed y-up to Right handed z-up
316         """
317         return (pos.x, pos.z, pos.y)
318
319
320     def convert_uv(uv):
321         return (uv.x, 1.0 - uv.y)
322
323
324     def getBoneName(bone):
325         name = englishmap.getEnglishBoneName(bone.getName())
326         return name if name else bone.getName()
327
328
329     def get_bone_name(l, index):
330         name=englishmap.getEnglishBoneName(l.bones[index].getName())
331         return name if name else l.bones[index].getName()
332
333
334     def create_texture(directory, texture_name):
335         texture=bpy.data.textures.new(texture_name)
336         texture.type='IMAGE'
337         texture=texture.recast_type()
338         texturePath=os.path.join(directory, texture_name)
339         print('create_texture', texturePath)
340         image=bpy.data.images.load(texturePath)
341         texture.image=image
342         texture.mipmap = True
343         texture.interpolation = True
344         texture.use_alpha = True
345         return texture
346
347
348     def build_bone(armature, b, parent=None):
349         if b.tail_index==0:
350             return
351
352         name=getBoneName(b)
353         bone = armature.edit_bones.new(name if name else b.getName())
354         if parent:
355             bone.head = mathutils.Vector(convert_coord(b.pos))
356             bone.parent=parent
357             bone.connected=True if parent.tail==bone.head else False
358             bone.tail = mathutils.Vector(convert_coord(b.tail))
359             if bone.head==bone.tail:
360                 bone.tail=bone.head-mathutils.Vector((0, 1, 0))
361         elif b.__class__ is pmd.BONE_IK:
362             bone.head = mathutils.Vector(convert_coord(b.pos))
363             bone.tail = mathutils.Vector(convert_coord(b.tail))
364         else:
365             # center
366             tail=mathutils.Vector(convert_coord(b.pos))
367             bone.tail = tail
368             bone.head = tail-mathutils.Vector((0, 1, 0))
369
370         for child in b.children:
371             build_bone(armature, child, bone)
372
373
374     def importArmature(scene, l):
375         # create armature
376         armature = bpy.data.armatures.new('Armature')
377         # link to object
378         armature_object=bpy.data.objects.new('Armature', armature)
379         scene.objects.link(armature_object)
380         armature_object.x_ray=True
381         armature.draw_names=True
382
383         # armature settings
384         armature.drawtype='OCTAHEDRAL'
385         armature.deform_envelope=False
386         armature.deform_vertexgroups=True
387         armature.x_axis_mirror=True
388
389         # create action
390         #act = Blender.Armature.NLA.NewAction()
391         #act.setActive(armature_object)
392
393         # select only armature object and set edit mode
394         scene.objects.active=armature_object
395         bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
396         bpy.ops.object.mode_set(mode='EDIT', toggle=False)
397
398         # create armature
399         for b in l.bones:
400             if not b.parent:
401                 build_bone(armature, b)
402
403         bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
404         bpy.ops.object.select_all(action='DESELECT')
405
406         ############################################################
407         # IK
408         ############################################################
409         pose = armature_object.pose
410         for ik in l.ik_list:
411             effector=l.bones[ik.target]
412             parent=l.bones[effector.parent_index]
413             name=getBoneName(parent)
414             p_bone = pose.bones[name]
415             if not p_bone:
416                 print('not found', name)
417                 continue
418             if len(ik.children) >= 16:
419                 print('over MAX_CHAINLEN', ik, len(ik.children))
420                 continue
421             # IK
422             ik_const = p_bone.constraints.new('IK')
423             ik_const.chain_length=len(ik.children)
424             ik_const.target=armature_object
425             ik_const.subtarget=getBoneName(l.bones[ik.index])
426             # ROT
427             rot_const = p_bone.constraints.new('LIMIT_ROTATION')
428             rot_const.influence = ik.weight
429             rot_const.owner_space = 'LOCAL'
430             rot_const.use_limit_x=True
431             rot_const.use_limit_z=True
432             rot_const.minimum_x=to_radian(ik.iterations)
433             rot_const.maximum_x=to_radian(180)
434             rot_const.minimum_z=to_radian(180 - ik.iterations)
435             rot_const.maximum_z=to_radian(0)
436
437         return armature_object
438         
439
440     def importShape(meshObject, l, vertex_map):
441         if len(l.morph_list)==0:
442             return
443
444         # base 
445         base=None
446         for s in l.morph_list:
447             if s.type!=0:
448                 continue
449             base=s
450             break
451         assert(base)
452
453         # create base key
454         baseblock=meshObject.add_shape_key("Basis")
455
456         # mesh
457         mesh=meshObject.data
458
459         # each skin
460         for s in l.morph_list:
461             if s.getName()==base.name:
462                 # skip base
463                 continue
464
465             # restore
466             #for v, base_pos in zip(mesh.verts, baseblock.data):
467             #    v.co=base_pos.co
468             #mesh.update()
469
470             # name
471             name=englishmap.getEnglishSkinName(s.getName())
472             if not name:
473                 name=s.getName()
474             new_shape_key=meshObject.add_shape_key(name)
475             #new_shape_key.value=1.0
476
477             # morph
478             for i, offset in zip(s.indices, s.pos_list):
479                 try:
480                     vertex_index=base.indices[i]
481                     new_shape_key.data[vertex_index].co=[p+o for p, o in zip(
482                         mesh.verts[vertex_index].co, convert_coord(offset))]
483                 except IndexError as msg:
484                     print(IndexError, msg)
485                     print(i, len(base.indices))
486                     print(vertex_index, len(mesh.verts))
487                     print(base.indices[i])
488                     break
489                 except KeyError:
490                     #print 'this mesh not has shape vertices'
491                     break
492             
493             # set ipo curve
494             #icu=ipo.addCurve(name)
495             #icu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
496             #icu.append( (0.0, 0.0) )
497
498
499 def __import16MaerialAndMesh(meshObject, l, 
500         material_order, face_map, tex_dir):
501
502     mesh=bl.objectGetData(meshObject)
503     ############################################################
504     # material
505     ############################################################
506     progress_print('create materials')
507     mesh_material_map={}
508     textureMap={}
509     imageMap={}
510     index=0
511
512     for material_index in material_order:
513         try:
514             m=l.materials[material_index]
515             mesh_material_map[material_index]=index
516         except KeyError:
517             break
518
519         material=bl.createPmdMaterial(m)
520
521         texture_name=m.getTexture()
522         #tex_file=re.compile('\*.*.spa$').sub('', m.getTexture())
523         #tex_path = os.path.join(tex_dir, tex_file).encode(
524         #        bl.INTERNAL_ENCODING)
525         if texture_name!='':
526             if texture_name in textureMap:
527                 texture=textureMap[texture_name]
528             else:
529                 try:
530                     texture, image=bl.createTexture(
531                             os.path.join(tex_dir, texture_name))
532                     textureMap[texture_name]=texture
533                     imageMap[material_index]=image
534                 except:
535                     continue
536             bl.materialAddTexture(material, texture)
537         bl.meshAddMaterial(mesh, material)
538         index+=1
539
540     ############################################################
541     # vertex
542     ############################################################
543     progress_print('create vertices')
544     # create vertices
545     vertices=[]
546     if isBlender24():
547         for v in l.each_vertex():
548             vertices.append(convert_coord(v.pos))
549     else:
550         for v in l.each_vertex():
551             vertices.extend(convert_coord(v.pos))
552
553     ############################################################
554     # face
555     ############################################################
556     progress_print('create faces')
557     # create faces
558     mesh_face_indices=[]
559     mesh_face_materials=[]
560     used_vertices=set()
561
562     for material_index in material_order:
563         face_offset=face_map[material_index]
564         m=l.materials[material_index]
565         material_faces=l.indices[face_offset:face_offset+m.vertex_count]
566
567         def degenerate(i0, i1, i2):
568             """
569             縮退しているか?
570             """
571             return i0==i1 or i1==i2 or i2==i0
572
573         for j in xrange(0, len(material_faces), 3):
574             i0=material_faces[j]
575             i1=material_faces[j+1]
576             i2=material_faces[j+2]
577             if i2==0:
578                 triangle=[i2, i0, i1]
579             else:
580                 triangle=[i0, i1, i2]
581             if degenerate(*triangle):
582                 continue
583             if isBlender24():
584                 mesh_face_indices.append(triangle[0:3])
585             else:
586                 mesh_face_indices.extend(
587                         [triangle[0], triangle[1], triangle[2], 0])
588             mesh_face_materials.append(material_index)
589             used_vertices.add(i0)
590             used_vertices.add(i1)
591             used_vertices.add(i2)
592
593     ############################################################
594     # create vertices & faces
595     ############################################################
596     bl.meshCreateVerteicesAndFaces(mesh, vertices, mesh_face_indices)
597
598     ############################################################
599     # vertex bone weight
600     ############################################################
601     # create vertex group
602     vertex_groups={}
603     for v in l.each_vertex():
604         vertex_groups[v.bone0]=True
605         vertex_groups[v.bone1]=True
606     for i in vertex_groups.keys():
607         bl.meshAddVertexGroup(meshObject, get_bone_name(l, i))
608
609     # vertex params
610     bl.meshUseVertexUv(mesh)
611     for i, v, mvert in zip(xrange(len(l.vertices)), 
612         l.each_vertex(), mesh.verts):
613         # normal, uv
614         bl.vertexSetNormal(mvert, convert_coord(v.normal))
615         bl.vertexSetUv(mvert, convert_uv(v.uv))
616         # bone weight
617         w1=float(v.weight0)/100.0
618         w2=1.0-w1
619         bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone0),
620             i,  w1)
621         bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone1),
622             i,  w2)
623
624     ############################################################
625     # face params
626     ############################################################
627     used_map={}
628     bl.meshAddUV(mesh)
629
630     if isBlender24():
631         for face, material_index in zip(mesh.faces, mesh_face_materials):
632             try:
633                 index=mesh_material_map[material_index]
634             except KeyError as message:
635                 print(message, mesh_material_map, m)
636                 assert(False)
637             face.mat=index
638             material=mesh.materials[index]
639             texture=material.getTextures()[0]
640             used_map[index]=True
641             if texture:
642                 face.image=texture.tex.image
643                 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
644                 face.uv=[
645                     face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
646             # set smooth
647             face.smooth = 1
648         # flip
649         mesh.flipNormals()
650     else:
651         for face, uv_face, material_index in zip(mesh.faces, 
652                 mesh.uv_textures[0].data,
653                 mesh_face_materials,
654                 ):
655             try:
656                 index=mesh_material_map[material_index]
657             except KeyError as message:
658                 print(message, mesh_material_map, m)
659                 assert(False)
660             face.material_index=index
661             material=mesh.materials[index]
662             used_map[index]=True
663             if material.texture_slots[0]:
664                 uv=l.getUV(face.verts[0])
665                 uv_face.uv1=[uv.x, 1.0-uv.y]
666
667                 uv=l.getUV(face.verts[1])
668                 uv_face.uv2=[uv.x, 1.0-uv.y]
669
670                 uv=l.getUV(face.verts[2])
671                 uv_face.uv3=[uv.x, 1.0-uv.y]
672             if face.material_index in imageMap:
673                 uv_face.image=imageMap[face.material_index]
674                 uv_face.tex=True
675
676             # set smooth
677             face.smooth = 1
678     mesh.update()
679
680     ############################################################
681     # clean up not used vertices
682     ############################################################
683     progress_print('clean up vertices not used')
684     remove_vertices=[]
685     vertex_map={}
686     for i, v in enumerate(l.each_vertex()):
687         if i in used_vertices:
688             vertex_map[i]=len(vertex_map)
689         else:
690             remove_vertices.append(i)
691
692     bl.meshVertsDelete(mesh, remove_vertices)
693
694     progress_print('%s created' % mesh.name)
695     return vertex_map
696
697
698 def __importMesh(scene, io, tex_dir):
699     """
700     @param l[in] mmd.PMDLoader
701     @param filename[in]
702     """
703     ############################################################
704     # shpaeキーで使われるマテリアル優先的に前に並べる
705     ############################################################
706     # shapeキーで使われる頂点インデックスを集める
707     shape_key_used_vertices=set()
708     if len(io.morph_list)>0:
709         # base 
710         base=None
711         for s in io.morph_list:
712             if s.type!=0:
713                 continue
714             base=s
715             break
716         assert(base)
717
718         for index in base.indices:
719             shape_key_used_vertices.add(index)
720
721     # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
722     def isMaterialUsedInShape(offset, m):
723         for i in xrange(offset, offset+m.vertex_count): 
724             if io.indices[i] in shape_key_used_vertices:
725                 return True
726
727     # shapeキーで使われるマテリアルを記録する
728     shape_key_materials=set()
729     # 各マテリアルの開始頂点インデックスを記録する
730     face_map={}
731     face_count=0
732     for i, m in enumerate(io.materials):
733         face_map[i]=face_count
734         if isMaterialUsedInShape(face_count, m):
735             shape_key_materials.add(i)
736         face_count+=m.vertex_count
737
738     # list化
739     material_order=list(shape_key_materials)
740
741     # shapeキーに使われていないマテリアルを後ろに追加
742     for i in range(len(io.materials)):
743         if not i in material_order:
744             material_order.append(i)
745
746     # マテリアル16個ごとに分割したメッシュを作成する
747     material_offset=0
748     mesh_objects=[]
749     while material_offset<len(io.materials):
750         mesh, meshObject=bl.createMesh(scene, 'mesh')
751         # create object
752         #meshObject.layers = [1]
753         mesh_objects.append(meshObject)
754
755         # activate object
756         bl.objectDeselectAll()
757         bl.objectActivate(scene, meshObject)
758
759         # shapeキーで使われる順に並べなおしたマテリアル16個分の
760         # メッシュを作成する
761         vertex_map=__import16MaerialAndMesh(
762                 meshObject, io, 
763                 material_order[material_offset:material_offset+16], 
764                 face_map, tex_dir)
765
766         # enter Edit Mode
767         bl.enterEditMode()
768
769         # crete shape key
770         importShape(meshObject, io, vertex_map)
771
772         # exit Edit Mode
773         bl.exitEditMode()
774
775         mesh.update()
776         material_offset+=16
777
778     return mesh_objects
779
780 def __execute(filename, scene):
781     """
782     load pmd file to context.
783     """
784     # load pmd
785     progress_set('load %s' % filename, 0.0)
786
787     io=pmd.IO()
788     if not io.read(filename):
789         print("fail to load %s" % filename)
790         return
791     progress_set('loaded %s' % filename, 0.1)
792
793     # create root object
794     root=bl.createEmptyObject(scene, 
795             io.english_name if len(io.english_name)>0 else io.getName().encode(bl.INTERNAL_ENCODING))
796
797     # import mesh
798     mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
799     for o in mesh_objects:
800         bl.objectMakeParent(root, o)
801
802     # import armature
803     armature_object=importArmature(scene, io)
804     if armature_object:
805         bl.objectMakeParent(root, armature_object)
806         armature = bl.objectGetData(armature_object) 
807
808         # add armature modifier
809         for o in mesh_objects:
810             bl.objectAddArmatureModifier(o, armature_object)
811
812         # Limitation
813         for n, b in bl.objectGetPose(armature_object).bones.items():
814             bl.poseBoneLimit(n, b)
815
816     # select objects
817     bl.objectSelect(root)
818     for o in mesh_objects:
819         bl.objectSelect(o)
820     bl.objectSelect(armature_object)
821  
822
823 if isBlender24():
824     # for 2.4
825     def execute_24(filename):
826         """
827         @param filename
828         """
829         filename=filename.decode(bl.INTERNAL_ENCODING)
830         print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
831
832         # set object mode
833         mode_edit = Blender.Window.EditMode() 
834         if mode_edit: 
835             Blender.Window.EditMode(0)
836             
837         progress_start('pmd_import')
838         scene = bpy.data.scenes.active
839         __execute(filename, scene)
840         scene.update(0)
841         progress_finish()
842
843         # restore edit mode
844         if mode_edit: 
845             Blender.Window.EditMode(1)
846         Blender.Window.RedrawAll()
847
848     Blender.Window.FileSelector(
849             execute_24, 
850             'Import PMD file', 
851             Blender.sys.makename(ext='.pmd'))
852
853 else:
854     # for 2.5
855     def execute_25(*args):
856         progress_start('pmd_import')
857         __execute(*args)
858         progress_finish()
859
860     # import operator
861     class IMPORT_OT_pmd(bpy.types.Operator):
862         bl_idname = "import_scene.pmd"
863         bl_label = 'Import PMD'
864
865         # List of operator properties, the attributes will be assigned
866         # to the class instance from the operator settings before calling.
867
868         path = StringProperty(
869                 name="File Path", 
870                 description="File path used for importing the PMD file", 
871                 maxlen= 1024, default= "")
872         filename = StringProperty(
873                 name="File Name", 
874                 description="Name of the file.")
875         directory = StringProperty(
876                 name="Directory", 
877                 description="Directory of the file.")
878
879         def execute(self, context):
880             execute_25(self.properties.path, context.scene)
881             return 'FINISHED'
882
883         def invoke(self, context, event):
884             wm = context.manager
885             wm.add_fileselect(self)
886             return 'RUNNING_MODAL'
887
888     # register menu
889     def menu_func(self, context): 
890         self.layout.operator(IMPORT_OT_pmd.bl_idname, 
891                 text="MikuMikuDance model (.pmd)")
892
893     def register():
894         bpy.types.register(IMPORT_OT_pmd)
895         bpy.types.INFO_MT_file_import.append(menu_func)
896
897     def unregister():
898         bpy.types.unregister(IMPORT_OT_pmd)
899         bpy.types.INFO_MT_file_import.remove(menu_func)
900
901     if __name__=="__main__":
902         register()
903