OSDN Git Service

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