OSDN Git Service

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