OSDN Git Service

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