OSDN Git Service

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