OSDN Git Service

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