OSDN Git Service

fix mqo_import smoothing, mirroring.
[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.2"
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 1.2: 20100616: implement rigid body.
28 1.3: 20100619: fix for various models.
29 """
30
31 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
32 BASE_SHAPE_NAME='Basis'
33 RIGID_SHAPE_TYPE='rigid_shape_type'
34 RIGID_PROCESS_TYPE='rigid_process_type'
35 RIGID_BONE_NAME='rigid_bone_name'
36 #RIGID_LOCATION='rigid_loation'
37 RIGID_GROUP='ribid_group'
38 RIGID_INTERSECTION_GROUP='rigid_intersection_group'
39 RIGID_WEIGHT='rigid_weight'
40 RIGID_LINEAR_DAMPING='rigid_linear_damping'
41 RIGID_ANGULAR_DAMPING='rigid_angular_damping'
42 RIGID_RESTITUTION='rigid_restitution'
43 RIGID_FRICTION='rigid_friction'
44 CONSTRAINT_A='const_a'
45 CONSTRAINT_B='const_b'
46 CONSTRAINT_POS_MIN='const_pos_min'
47 CONSTRAINT_POS_MAX='const_pos_max'
48 CONSTRAINT_ROT_MIN='const_rot_min'
49 CONSTRAINT_ROT_MAX='const_rot_max'
50 CONSTRAINT_SPRING_POS='const_spring_pos'
51 CONSTRAINT_SPRING_ROT='const_spring_rot'
52
53
54 ###############################################################################
55 # import
56 ###############################################################################
57 import os
58 import sys
59 import math
60
61 # C extension
62 from meshio import pmd, englishmap
63
64 def isBlender24():
65     return sys.version_info[0]<3
66
67 if isBlender24():
68     # for 2.4
69     import Blender
70     from Blender import Mathutils
71     import bpy
72
73     # wrapper
74     import bl24 as bl
75 else:
76     # for 2.5
77     import bpy
78     from bpy.props import *
79     import mathutils
80
81     # wrapper
82     import bl25 as bl
83
84     xrange=range
85
86 ###############################################################################
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 to_radian(degree):
99     return math.pi * degree / 180
100
101
102 def get_bone_name(l, index):
103     if index==0xFFFF:
104         return l.bones[0].getName()
105
106     if index < len(l.bones):
107         name=englishmap.getEnglishBoneName(l.bones[index].getName())
108         if name:
109             return name
110         return l.bones[index].getName()
111     print('invalid bone index', index)
112     return l.bones[0].getName()
113
114 def __importShape(obj, l, vertex_map):
115     if len(l.morph_list)==0:
116         return
117
118     # set shape_key pin
119     bl.objectPinShape(obj)
120
121     # find base 
122     base=None
123     for s in l.morph_list:
124         if s.type==0:
125             base=s
126
127             # create vertex group
128             bl.meshAddVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
129             hasShape=False
130             for i in s.indices:
131                 if i in vertex_map:
132                     hasShape=True
133                     bl.meshAssignVertexGroup(
134                             obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
135             if not hasShape:
136                 return
137     assert(base)
138
139     # create base key
140     baseShapeBlock=bl.objectAddShapeKey(obj, BASE_SHAPE_NAME)
141     # mesh
142     mesh=bl.objectGetData(obj)
143     mesh.update()
144
145     # each skin
146     for s in l.morph_list:
147         if s.type==0:
148             continue
149
150         # name
151         name=englishmap.getEnglishSkinName(s.getName())
152         if not name:
153             name=s.getName()
154
155         if isBlender24():
156             # 24
157             for index, offset in zip(s.indices, s.pos_list):
158                 try:
159                     vertex_index=vertex_map[base.indices[index]]
160                     v=mesh.verts[vertex_index].co
161                     offset=convert_coord(offset)
162                     v[0]+=offset[0]
163                     v[1]+=offset[1]
164                     v[2]+=offset[2]
165                 except IndexError as msg:
166                     print(msg)
167                     print(index, len(base.indices), len(vertex_map))
168                     print(len(mesh.verts))
169                     print(base.indices[index])
170                     print(vertex_index)
171                     break
172                 except KeyError:
173                     #print 'this mesh not has shape vertices'
174                     break
175
176             # create shapekey block
177             new_shape_key=bl.objectAddShapeKey(obj, name)
178
179             # copy vertex to shape key
180             mesh.update()
181             
182             # restore
183             for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
184                 mv.co[0] = v[0]
185                 mv.co[1] = v[1]
186                 mv.co[2] = v[2]
187             mesh.update()
188
189         else:
190             # 25
191             new_shape_key=bl.objectAddShapeKey(obj, name)
192
193             for index, offset in zip(s.indices, s.pos_list):
194                 try:
195                     vertex_index=vertex_map[base.indices[index]]
196                     bl.shapeKeyAssign(new_shape_key, vertex_index,
197                             mesh.verts[vertex_index].co+
198                             bl.createVector(*convert_coord(offset)))
199                 except IndexError as msg:
200                     print(msg)
201                     print(index, len(base.indices), len(vertex_map))
202                     print(len(mesh.verts))
203                     print(base.indices[index])
204                     print(vertex_index)
205                     break
206                 except KeyError:
207                     #print 'this mesh not has shape vertices'
208                     break
209
210     # select base shape
211     bl.objectActivateShapeKey(obj, 0)
212
213
214 def __build(armature, b, p, parent):
215     name=englishmap.getEnglishBoneName(b.getName())
216     if not name:
217         name=b.getName()
218
219     bone=bl.createArmatureBone(armature, name)
220
221     if parent and (b.tail_index==0 or b.type==6 or b.type==7 or b.type==9):
222         bone.head = bl.createVector(*convert_coord(b.pos))
223         bone.tail=bone.head+bl.createVector(0, 1, 0)
224         bone.parent=parent
225         if bone.name=="center_t":
226             # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
227             parent.tail=parent.head+bl.createVector(0, 1, 0)
228             bone.head=parent.tail
229             bone.tail=bone.head+bl.createVector(0, 1, 0)
230         else:
231             if parent.tail==bone.head:
232                 pass
233             else:
234                 print('diffurence with parent.tail and head', name)
235
236         bl.boneSetConnected(bone)
237         # armature layer 2
238         bl.boneLayerMask(bone, [0, 1])
239     else:
240         # 通常ボーン
241         bone.head = bl.createVector(*convert_coord(b.pos))
242         bone.tail = bl.createVector(*convert_coord(b.tail))
243         if parent:
244             bone.parent=parent
245             if parent.tail==bone.head:
246                 bl.boneSetConnected(bone)
247
248     if bone.head==bone.tail:
249         bone.tail=bone.head+bl.createVector(0, 1, 0)
250
251     for c in b.children:
252         __build(armature, c, b, bone)
253
254
255 def __importArmature(scene, l):
256     # build bone
257     armature, armature_object=bl.createArmature(scene)
258     bl.armatureMakeEditable(scene, armature_object)
259     for b in l.bones:
260         if not b.parent:
261             __build(armature, b, None, None)
262     bl.armatureUpdate(armature)
263     bl.exitEditMode()
264
265     # IK constraint
266     pose = bl.objectGetPose(armature_object)
267     for ik in l.ik_list:
268         target=l.bones[ik.target]
269         name = englishmap.getEnglishBoneName(target.getName())
270         if not name:
271             name=target.getName()
272         p_bone = pose.bones[name]
273         if not p_bone:
274             print('not found', name)
275             continue
276         if len(ik.children) >= 16:
277             print('over MAX_CHAINLEN', ik, len(ik.children))
278             continue
279         effector_name=englishmap.getEnglishBoneName(
280                 l.bones[ik.index].getName())
281         if not effector_name:
282             effector_name=l.bones[ik.index].getName()
283
284         constraint=bl.createIkConstraint(armature_object, 
285                 p_bone, effector_name, ik)
286
287     bl.armatureMakeEditable(scene, armature_object)
288     bl.armatureUpdate(armature)
289     bl.exitEditMode()
290
291     return armature_object
292         
293
294 def __import16MaerialAndMesh(meshObject, l, 
295         material_order, face_map, tex_dir):
296
297     mesh=bl.objectGetData(meshObject)
298     ############################################################
299     # material
300     ############################################################
301     bl.progress_print('create materials')
302     mesh_material_map={}
303     textureMap={}
304     imageMap={}
305     index=0
306
307     for material_index in material_order:
308         try:
309             m=l.materials[material_index]
310             mesh_material_map[material_index]=index
311         except KeyError:
312             break
313
314         material=bl.createPmdMaterial(m)
315
316         texture_name=m.getTexture()
317         if texture_name!='':
318             if texture_name in textureMap:
319                 texture=textureMap[texture_name]
320             else:
321                 try:
322                     texture, image=bl.createTexture(
323                             os.path.join(tex_dir, texture_name))
324                     textureMap[texture_name]=texture
325                     imageMap[material_index]=image
326                 except:
327                     continue
328             bl.materialAddTexture(material, texture)
329         bl.meshAddMaterial(mesh, material)
330         index+=1
331
332     ############################################################
333     # vertex
334     ############################################################
335     bl.progress_print('create vertices')
336     # create vertices
337     vertices=[]
338     if isBlender24():
339         for v in l.each_vertex():
340             vertices.append(convert_coord(v.pos))
341     else:
342         for v in l.each_vertex():
343             vertices.extend(convert_coord(v.pos))
344
345     ############################################################
346     # face
347     ############################################################
348     bl.progress_print('create faces')
349     # create faces
350     mesh_face_indices=[]
351     mesh_face_materials=[]
352     used_vertices=set()
353
354     for material_index in material_order:
355         face_offset=face_map[material_index]
356         m=l.materials[material_index]
357         material_faces=l.indices[face_offset:face_offset+m.vertex_count]
358
359         def degenerate(i0, i1, i2):
360             """
361             縮退しているか?
362             """
363             return i0==i1 or i1==i2 or i2==i0
364
365         for j in xrange(0, len(material_faces), 3):
366             i0=material_faces[j]
367             i1=material_faces[j+1]
368             i2=material_faces[j+2]
369             if i2==0:
370                 triangle=[i2, i0, i1]
371             else:
372                 triangle=[i0, i1, i2]
373             if degenerate(*triangle):
374                 continue
375             if isBlender24():
376                 mesh_face_indices.append(triangle[0:3])
377             else:
378                 mesh_face_indices.extend(
379                         [triangle[0], triangle[1], triangle[2], 0])
380             mesh_face_materials.append(material_index)
381             used_vertices.add(i0)
382             used_vertices.add(i1)
383             used_vertices.add(i2)
384
385     ############################################################
386     # create vertices & faces
387     ############################################################
388     bl.meshCreateVerteicesAndFaces(mesh, vertices, mesh_face_indices)
389
390     ############################################################
391     # vertex bone weight
392     ############################################################
393     # create vertex group
394     vertex_groups={}
395     for v in l.each_vertex():
396         vertex_groups[v.bone0]=True
397         vertex_groups[v.bone1]=True
398     for i in vertex_groups.keys():
399         bl.meshAddVertexGroup(meshObject, get_bone_name(l, i))
400
401     # vertex params
402     bl.meshUseVertexUv(mesh)
403     for i, v, mvert in zip(xrange(len(l.vertices)), 
404         l.each_vertex(), mesh.verts):
405         # normal, uv
406         bl.vertexSetNormal(mvert, convert_coord(v.normal))
407         bl.vertexSetUv(mvert, convert_uv(v.uv))
408         # bone weight
409         w1=float(v.weight0)/100.0
410         w2=1.0-w1
411         bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone0),
412             i,  w1)
413         bl.meshAssignVertexGroup(meshObject, get_bone_name(l, v.bone1),
414             i,  w2)
415
416     ############################################################
417     # face params
418     ############################################################
419     used_map={}
420     bl.meshAddUV(mesh)
421
422     if isBlender24():
423         for face, material_index in zip(mesh.faces, mesh_face_materials):
424             try:
425                 index=mesh_material_map[material_index]
426             except KeyError as message:
427                 print(message, mesh_material_map, m)
428                 assert(False)
429             face.mat=index
430             material=mesh.materials[index]
431             texture=material.getTextures()[0]
432             used_map[index]=True
433             if texture:
434                 face.image=texture.tex.image
435                 texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
436                 face.uv=[
437                     face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
438             # set smooth
439             face.smooth = 1
440         # flip
441         mesh.flipNormals()
442     else:
443         for face, uv_face, material_index in zip(mesh.faces, 
444                 mesh.uv_textures[0].data,
445                 mesh_face_materials,
446                 ):
447             try:
448                 index=mesh_material_map[material_index]
449             except KeyError as message:
450                 print(message, mesh_material_map, m)
451                 assert(False)
452             face.material_index=index
453             material=mesh.materials[index]
454             used_map[index]=True
455             if material.texture_slots[0]:
456                 uv=l.getUV(face.verts[0])
457                 uv_face.uv1=[uv.x, 1.0-uv.y]
458
459                 uv=l.getUV(face.verts[1])
460                 uv_face.uv2=[uv.x, 1.0-uv.y]
461
462                 uv=l.getUV(face.verts[2])
463                 uv_face.uv3=[uv.x, 1.0-uv.y]
464             if face.material_index in imageMap:
465                 uv_face.image=imageMap[face.material_index]
466                 uv_face.tex=True
467
468             # set smooth
469             face.smooth = 1
470     mesh.update()
471
472     ############################################################
473     # clean up not used vertices
474     ############################################################
475     bl.progress_print('clean up vertices not used')
476     remove_vertices=[]
477     vertex_map={}
478     for i, v in enumerate(l.each_vertex()):
479         if i in used_vertices:
480             vertex_map[i]=len(vertex_map)
481         else:
482             remove_vertices.append(i)
483
484     bl.meshVertsDelete(mesh, remove_vertices)
485
486     bl.progress_print('%s created' % mesh.name)
487     return vertex_map
488
489
490 def __importMesh(scene, io, tex_dir):
491     """
492     @param l[in] mmd.PMDLoader
493     @param filename[in]
494     """
495     ############################################################
496     # shpaeキーで使われるマテリアル優先的に前に並べる
497     ############################################################
498     # shapeキーで使われる頂点インデックスを集める
499     shape_key_used_vertices=set()
500     if len(io.morph_list)>0:
501         # base 
502         base=None
503         for s in io.morph_list:
504             if s.type!=0:
505                 continue
506             base=s
507             break
508         assert(base)
509
510         for index in base.indices:
511             shape_key_used_vertices.add(index)
512
513     # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
514     def isMaterialUsedInShape(offset, m):
515         for i in xrange(offset, offset+m.vertex_count): 
516             if io.indices[i] in shape_key_used_vertices:
517                 return True
518
519     # shapeキーで使われるマテリアルを記録する
520     shape_key_materials=set()
521     # 各マテリアルの開始頂点インデックスを記録する
522     face_map={}
523     face_count=0
524     for i, m in enumerate(io.materials):
525         face_map[i]=face_count
526         if isMaterialUsedInShape(face_count, m):
527             shape_key_materials.add(i)
528         face_count+=m.vertex_count
529
530     # list化
531     material_order=list(shape_key_materials)
532
533     # shapeキーに使われていないマテリアルを後ろに追加
534     for i in range(len(io.materials)):
535         if not i in material_order:
536             material_order.append(i)
537
538     # マテリアル16個ごとに分割したメッシュを作成する
539     material_offset=0
540     mesh_objects=[]
541     while material_offset<len(io.materials):
542         mesh, meshObject=bl.createMesh(scene, 'mesh')
543         # create object
544         mesh_objects.append(meshObject)
545
546         # activate object
547         bl.objectDeselectAll()
548         bl.objectActivate(scene, meshObject)
549
550         # shapeキーで使われる順に並べなおしたマテリアル16個分の
551         # メッシュを作成する
552         vertex_map=__import16MaerialAndMesh(
553                 meshObject, io, 
554                 material_order[material_offset:material_offset+16], 
555                 face_map, tex_dir)
556
557         # enter Edit Mode
558         #bl.enterEditMode()
559
560         # crete shape key
561         __importShape(meshObject, io, vertex_map)
562
563         # exit Edit Mode
564         #bl.exitEditMode()
565
566         mesh.update()
567         material_offset+=16
568
569     return mesh_objects
570
571
572 def __importConstraints(scene, io):
573     if isBlender24():
574         return
575     print("create constrains")
576     container=bl.createEmptyObject(scene, 'Constraints')
577     layer=[
578             True, False, False, False, False, False, False, False,
579             False, False, False, False, False, False, False, False,
580             False, False, False, False, False, False, False, False,
581             False, False, False, False, False, False, False, False,
582             ]
583     material=bl.createMaterial('constraint')
584     material.diffuse_color=(1, 0, 0)
585     constraintMeshes=[]
586     for c in io.constraints:
587         bpy.ops.mesh.primitive_uv_sphere_add(
588                 segments=8,
589                 rings=4,
590                 size=0.1,
591                 location=(c.pos.x, c.pos.z, c.pos.y),
592                 layer=layer
593                 )
594         meshObject=scene.objects.active
595         constraintMeshes.append(meshObject)
596         mesh=bl.objectGetData(meshObject)
597         bl.meshAddMaterial(mesh, material)
598         meshObject.name='c'+c.getName()
599         #meshObject.draw_transparent=True
600         #meshObject.draw_wire=True
601         meshObject.max_draw_type='SOLID'
602         rot=c.rot
603         meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
604
605         meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
606         meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
607         meshObject[CONSTRAINT_POS_MIN]=bl.VtoV(c.constraintPosMin)
608         meshObject[CONSTRAINT_POS_MAX]=bl.VtoV(c.constraintPosMax)
609         meshObject[CONSTRAINT_ROT_MIN]=bl.VtoV(c.constraintRotMin)
610         meshObject[CONSTRAINT_ROT_MAX]=bl.VtoV(c.constraintRotMax)
611         meshObject[CONSTRAINT_SPRING_POS]=bl.VtoV(c.springPos)
612         meshObject[CONSTRAINT_SPRING_ROT]=bl.VtoV(c.springRot)
613
614     for meshObject in reversed(constraintMeshes):
615         bl.objectMakeParent(container, meshObject)
616
617     return container
618
619
620 def __importRigidBodies(scene, io):
621     if isBlender24():
622         return
623     print("create rigid bodies")
624
625     container=bl.createEmptyObject(scene, 'RigidBodies')
626     layer=[
627             True, False, False, False, False, False, False, False,
628             False, False, False, False, False, False, False, False,
629             False, False, False, False, False, False, False, False,
630             False, False, False, False, False, False, False, False,
631             ]
632     material=bl.createMaterial('rigidBody')
633     rigidMeshes=[]
634     for rigid in io.rigidbodies:
635         if rigid.boneIndex==0xFFFF:
636             # no reference bone
637             bone=io.bones[0]
638         else:
639             bone=io.bones[rigid.boneIndex]
640         pos=bone.pos+rigid.position
641
642         if rigid.shapeType==pmd.SHAPE_SPHERE:
643             bpy.ops.mesh.primitive_ico_sphere_add(
644                     location=(pos.x, pos.z, pos.y),
645                     layer=layer
646                     )
647             bpy.ops.transform.resize(
648                     value=(rigid.w, rigid.w, rigid.w))
649         elif rigid.shapeType==pmd.SHAPE_BOX:
650             bpy.ops.mesh.primitive_cube_add(
651                     location=(pos.x, pos.z, pos.y),
652                     layer=layer
653                     )
654             bpy.ops.transform.resize(
655                     value=(rigid.w, rigid.d, rigid.h))
656         elif rigid.shapeType==pmd.SHAPE_CAPSULE:
657             bpy.ops.mesh.primitive_tube_add(
658                     location=(pos.x, pos.z, pos.y),
659                     layer=layer
660                     )
661             bpy.ops.transform.resize(
662                     value=(rigid.w, rigid.w, rigid.h))
663         else:
664             assert(False)
665
666         meshObject=scene.objects.active
667         mesh=bl.objectGetData(meshObject)
668         rigidMeshes.append(meshObject)
669         bl.meshAddMaterial(mesh, material)
670         meshObject.name=rigid.getName()
671         #meshObject.draw_transparent=True
672         #meshObject.draw_wire=True
673         meshObject.max_draw_type='WIRE'
674         rot=rigid.rotation
675         meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
676
677         # custom properties
678         meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
679         meshObject[RIGID_PROCESS_TYPE]=rigid.processType
680
681         bone_name = englishmap.getEnglishBoneName(bone.getName())
682         if not bone_name:
683             bone_name=bone.getName()
684         meshObject[RIGID_BONE_NAME]=bone_name
685
686         #meshObject[RIGID_LOCATION]=bl.VtoV(rigid.location)
687         meshObject[RIGID_GROUP]=rigid.group
688         meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
689         meshObject[RIGID_WEIGHT]=rigid.weight
690         meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
691         meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
692         meshObject[RIGID_RESTITUTION]=rigid.restitution
693         meshObject[RIGID_FRICTION]=rigid.friction
694
695     for meshObject in reversed(rigidMeshes):
696         bl.objectMakeParent(container, meshObject)
697
698     return container
699
700
701 def __execute(filename, scene):
702     """
703     load pmd file to context.
704     """
705     bl.progress_start('pmd_import')
706
707     # load pmd
708     bl.progress_set('load %s' % filename, 0.0)
709
710     io=pmd.IO()
711     if not io.read(filename):
712         print("fail to load %s" % filename)
713         return
714     bl.progress_set('loaded %s' % filename, 0.1)
715
716     # create root object
717     model_name=io.getEnglishName()
718     if len(model_name)==0:
719         model_name=io.getName()
720     root=bl.createEmptyObject(scene, model_name)
721
722     # import mesh
723     mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
724     for o in mesh_objects:
725         bl.objectMakeParent(root, o)
726
727     # import armature
728     armature_object=__importArmature(scene, io)
729     if armature_object:
730         bl.objectMakeParent(root, armature_object)
731         armature = bl.objectGetData(armature_object) 
732
733         # add armature modifier
734         for o in mesh_objects:
735             bl.objectAddArmatureModifier(o, armature_object)
736
737         # Limitation
738         for n, b in bl.objectGetPose(armature_object).bones.items():
739             bl.poseBoneLimit(n, b)
740
741     # import rigid bodies
742     rigidBodies=__importRigidBodies(scene, io)
743     if rigidBodies:
744         bl.objectMakeParent(root, rigidBodies)
745
746     # import constraints
747     constraints=__importConstraints(scene, io)
748     if constraints:
749         bl.objectMakeParent(root, constraints)
750
751     bl.objectActivate(scene, root)
752     bl.progress_finish()
753
754 if isBlender24():
755     # for 2.4
756     def execute_24(filename):
757         """
758         @param filename
759         """
760         filename=filename.decode(bl.INTERNAL_ENCODING)
761         print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
762
763         # set object mode
764         mode_edit = Blender.Window.EditMode() 
765         if mode_edit: 
766             Blender.Window.EditMode(0)
767             
768         scene = bpy.data.scenes.active
769         __execute(filename, scene)
770         scene.update(0)
771
772         # restore edit mode
773         if mode_edit: 
774             Blender.Window.EditMode(1)
775         Blender.Window.RedrawAll()
776
777     Blender.Window.FileSelector(
778             execute_24, 
779             'Import PMD file', 
780             Blender.sys.makename(ext='.pmd'))
781
782 else:
783     # for 2.5
784     def execute_25(*args):
785         __execute(*args)
786
787     # import operator
788     class IMPORT_OT_pmd(bpy.types.Operator):
789         bl_idname = "import_scene.pmd"
790         bl_label = 'Import PMD'
791
792         # List of operator properties, the attributes will be assigned
793         # to the class instance from the operator settings before calling.
794
795         path = StringProperty(
796                 name="File Path", 
797                 description="File path used for importing the PMD file", 
798                 maxlen= 1024, default= "")
799         filename = StringProperty(
800                 name="File Name", 
801                 description="Name of the file.")
802         directory = StringProperty(
803                 name="Directory", 
804                 description="Directory of the file.")
805
806         def execute(self, context):
807             execute_25(self.properties.path, context.scene)
808             return 'FINISHED'
809
810         def invoke(self, context, event):
811             wm = context.manager
812             wm.add_fileselect(self)
813             return 'RUNNING_MODAL'
814
815     # register menu
816     def menu_func(self, context): 
817         self.layout.operator(IMPORT_OT_pmd.bl_idname, 
818                 text="MikuMikuDance model (.pmd)")
819
820     def register():
821         bpy.types.register(IMPORT_OT_pmd)
822         bpy.types.INFO_MT_file_import.append(menu_func)
823
824     def unregister():
825         bpy.types.unregister(IMPORT_OT_pmd)
826         bpy.types.INFO_MT_file_import.remove(menu_func)
827
828     if __name__=="__main__":
829         register()
830