OSDN Git Service

add integrate pmd_import.
authorousttrue <ousttrue@gmail.com>
Mon, 7 Jun 2010 21:06:39 +0000 (06:06 +0900)
committerousttrue <ousttrue@gmail.com>
Mon, 7 Jun 2010 21:09:48 +0000 (06:09 +0900)
swig/blender/Makefile
swig/blender/bl24.py
swig/blender/bl25.py
swig/blender/cp.py
swig/blender/pmd_import.py [new file with mode: 0644]

index 1e2dfbb..2793516 100644 (file)
@@ -1,5 +1,5 @@
 all: copy
 
-copy: bl24.py bl25.py mqo_import.py mqo_export.py
+copy: bl24.py bl25.py mqo_import.py mqo_export.py pmd_import.py
        /cygdrive/C/Python26/python cp.py $^
 
index 0cce8a3..81220e6 100644 (file)
@@ -5,8 +5,8 @@ import Blender
 from Blender import Mathutils
 
 
-# \e$B%U%!%$%k%7%9%F%`$NJ8;z%3!<%I\e(B
-# \e$B2~B$HG$H$N6&MQ$N$?$a\e(B
+# ファイルシステムの文字コード
+# 改造版との共用のため
 FS_ENCODING=sys.getfilesystemencoding()
 if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
     INTERNAL_ENCODING='utf-8'
@@ -14,6 +14,9 @@ else:
     INTERNAL_ENCODING=FS_ENCODING
 
 
+###############################################################################
+# Writer
+###############################################################################
 class Writer(object):
     def __init__(self, path, encoding):
         self.io=open(path, "wb")
@@ -29,117 +32,36 @@ class Writer(object):
         self.io.close()
 
 
-def createEmptyObject(scene, name):
-    empty=scene.objects.new("Empty")
-    empty.setName(name)
-    return empty
-
-
-def createMqoMaterial(m):
-    material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
-    material.mode |= Blender.Material.Modes.SHADELESS
-    material.rgbCol = [m.color.r, m.color.g, m.color.b]
-    material.alpha = m.color.a
-    material.amb = m.ambient
-    material.spec = m.specular
-    material.hard = int(255 * m.power)
-    return material
-
-
-def createTexture(path):
-    image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
-    texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
-    texture.type = Blender.Texture.Types.IMAGE
-    texture.image = image
-    return texture, image
-
-
-def materialAddTexture(material, texture):
-    material.mode = material.mode | Blender.Material.Modes.TEXFACE
-    material.setTexture(0, texture, Blender.Texture.TexCo.UV)
-
-
-def createMesh(scene, name):
-    mesh = Blender.Mesh.New()
-    mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
-    return mesh, mesh_object
-
-
-def objectMakeParent(parent, child):
-    parent.makeParent([child])
-
-
-def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
-    # add vertices
-    mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
-    mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
-    # add faces
-    mesh_faces=[]
-    for face in o.faces:
-        face_indices=[]
-        for i in xrange(face.index_count):
-            face_indices.append(face.getIndex(i)+1)
-        mesh_faces.append(face_indices)
-    #new_faces=mesh.faces.extend([face.indices for face in o.faces], 
-    new_faces=mesh.faces.extend(mesh_faces,
-            #ignoreDups=True, 
-            indexList=True)
-    mesh.update()
-    
-    # gather used materials
-    materialMap = {}
-    if new_faces:
-        for i in new_faces:
-            if type(i) is int:
-                materialMap[o.faces[i].material_index]=True
-
-    # blender limits 16 materials per mesh
-    # separate mesh ?
-    for i, material_index in enumerate(materialMap.keys()):
-        if i>=16:
-            print("over 16 materials!")
-            break
-        mesh.materials+=[materials[material_index]]
-        materialMap[material_index]=i
-    
-    # set face params
-    for i, f in enumerate(o.faces):       
-        if not type(new_faces[i]) is int:
-            continue
-
-        face=mesh.faces[new_faces[i]]
-
-        uv_array=[]
-        for i in xrange(f.index_count):
-            uv_array.append(Blender.Mathutils.Vector(
-                f.getUV(i).x, 
-                1.0-f.getUV(i).y)
-                )
-        try:
-            face.uv=uv_array
-        except Exception as msg:
-            #print msg
-            #print face.index, uv_array
-            pass
-    
-        if f.material_index in materialMap:
-            face.mat = materialMap[f.material_index]
-
-        face.smooth = 1
-
-    # rmeove dummy 0 vertex
-    mesh.verts.delete(0)
-        
-    mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
-    mesh.maxSmoothAngle = int(o.smoothing)
-    mesh.smooth()
-    mesh.calcNormals()
-    mesh.flipNormals()
-    mesh.update()
+###############################################################################
+# ProgressBar
+###############################################################################
+class ProgressBar(object):
+    def __init__(self, base):
+        print "#### %s ####" % base
+        self.base=base
+        self.start=Blender.sys.time() 
+        self.set('<start>', 0)
+
+    def advance(self, message, progress):
+        self.progress+=float(progress)
+        self._print(message)
+
+    def set(self, message, progress):
+        self.progress=float(progress)
+        self._print(message)
+
+    def _print(self, message):
+        print message
+        message="%s: %s" % (self.base, message)
+        if message.__class__ is unicode:
+            message=message.encode(FS_ENCODING)
+        Blender.Window.DrawProgressBar(self.progress, message)
+
+    def finish(self):
+        self.progress=1.0
+        message='finished in %.2f sec' % (Blender.sys.time()-self.start)
+        self.set(message, 1.0)
 
-    # mirror modifier
-    if o.mirror:
-        mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
 
 ###############################################################################
 # for mqo mikoto bone.
@@ -345,8 +267,8 @@ def create_armature(scene, mqo):
 
 class TrianglePlane(object):
     """
-    mikoto\e$BJ}<0%\!<%s$N%"%s%+!<%&%'%$%H7W;;MQ!#\e(B
-    (\e$BIT40A4\e(B)
+    mikoto方式ボーンのアンカーウェイト計算用。
+    (不完全)
     """
     __slots__=['normal', 
             'v0', 'v1', 'v2',
@@ -404,7 +326,7 @@ class TrianglePlane(object):
 
 class MikotoAnchor(object):
     """
-    mikoto\e$BJ}<0%9%1%k%H%s$N%"%s%+!<!#\e(B
+    mikoto方式スケルトンのアンカー。
     """
     __slots__=[
             "triangles", "bbox",
@@ -527,6 +449,118 @@ def create_bone_weight(scene, mqo, armature_object, objects):
         mesh.update()
 
 ###############################################################################
+def createEmptyObject(scene, name):
+    empty=scene.objects.new("Empty")
+    empty.setName(name)
+    return empty
+
+
+def createMqoMaterial(m):
+    material = Blender.Material.New(m.getName().encode(INTERNAL_ENCODING))
+    material.mode |= Blender.Material.Modes.SHADELESS
+    material.rgbCol = [m.color.r, m.color.g, m.color.b]
+    material.alpha = m.color.a
+    material.amb = m.ambient
+    material.spec = m.specular
+    material.hard = int(255 * m.power)
+    return material
+
+
+def createTexture(path):
+    image = Blender.Image.Load(path.encode(INTERNAL_ENCODING))
+    texture = Blender.Texture.New(path.encode(INTERNAL_ENCODING))
+    texture.type = Blender.Texture.Types.IMAGE
+    texture.image = image
+    return texture, image
+
+
+def materialAddTexture(material, texture):
+    material.mode = material.mode | Blender.Material.Modes.TEXFACE
+    material.setTexture(0, texture, Blender.Texture.TexCo.UV)
+
+
+def createMesh(scene, name):
+    mesh = Blender.Mesh.New()
+    mesh_object=scene.objects.new(mesh, name.encode(INTERNAL_ENCODING))
+    return mesh, mesh_object
+
+
+def objectMakeParent(parent, child):
+    parent.makeParent([child])
+
+
+def meshAddMqoGeometry(mesh, o, materials, imageMap, scale):
+    # add vertices
+    mesh.verts.extend(Mathutils.Vector(0, 0, 0)) # dummy
+    mesh.verts.extend([(v.x, -v.z, v.y) for v in o.vertices])
+    # add faces
+    mesh_faces=[]
+    for face in o.faces:
+        face_indices=[]
+        for i in xrange(face.index_count):
+            face_indices.append(face.getIndex(i)+1)
+        mesh_faces.append(face_indices)
+    #new_faces=mesh.faces.extend([face.indices for face in o.faces], 
+    new_faces=mesh.faces.extend(mesh_faces,
+            #ignoreDups=True, 
+            indexList=True)
+    mesh.update()
+    
+    # gather used materials
+    materialMap = {}
+    if new_faces:
+        for i in new_faces:
+            if type(i) is int:
+                materialMap[o.faces[i].material_index]=True
+
+    # blender limits 16 materials per mesh
+    # separate mesh ?
+    for i, material_index in enumerate(materialMap.keys()):
+        if i>=16:
+            print("over 16 materials!")
+            break
+        mesh.materials+=[materials[material_index]]
+        materialMap[material_index]=i
+    
+    # set face params
+    for i, f in enumerate(o.faces):       
+        if not type(new_faces[i]) is int:
+            continue
+
+        face=mesh.faces[new_faces[i]]
+
+        uv_array=[]
+        for i in xrange(f.index_count):
+            uv_array.append(Blender.Mathutils.Vector(
+                f.getUV(i).x, 
+                1.0-f.getUV(i).y)
+                )
+        try:
+            face.uv=uv_array
+        except Exception as msg:
+            #print msg
+            #print face.index, uv_array
+            pass
+    
+        if f.material_index in materialMap:
+            face.mat = materialMap[f.material_index]
+
+        face.smooth = 1
+
+    # rmeove dummy 0 vertex
+    mesh.verts.delete(0)
+        
+    mesh.mode |= Blender.Mesh.Modes.AUTOSMOOTH
+    mesh.maxSmoothAngle = int(o.smoothing)
+    mesh.smooth()
+    mesh.calcNormals()
+    mesh.flipNormals()
+    mesh.update()
+
+    # mirror modifier
+    if o.mirror:
+        mod=mesh_object.modifiers.append(Blender.Modifier.Types.MIRROR)
+
 def getTexture(m, dirname):
     tex=""
     aplane=""
@@ -538,7 +572,7 @@ def getTexture(m, dirname):
                 continue
             imagePath=Blender.sys.expandpath(image.getFilename())
             if len(dirname)>0 and imagePath.startswith(dirname):
-                # \e$BAjBP%Q%9$KJQ49$9$k\e(B
+                # 相対パスに変換する
                 imagePath=imagePath[len(dirname)+1:len(imagePath)]
             if texture.mtCol>0:
                 tex=" tex(\"%s\")" % imagePath
@@ -578,3 +612,29 @@ def materialToMqo(m):
 def faceMaterialIndex(face):
     return face.mat
 
+def objectGetData(o):
+    return o.getData(mesh=True)
+
+def objectAddArmatureModifier(o, armature_object):
+    mod=o.modifiers.append(Blender.Modifier.Types.ARMATURE)
+    mod[Blender.Modifier.Settings.OBJECT] = armature_object
+    mod[Blender.Modifier.Settings.ENVELOPES] = False
+
+def objectSelect(o):
+    o.select(True)
+
+def objectGetPose(o):
+    return o.getPose()
+
+def poseBoneLimit(n, b):
+    if n.endswith("_t"):
+        return
+    if n.startswith("knee_"):
+        b.lockYRot=True
+        b.lockZRot=True
+        b.limitX=True
+        b.limitMin=[0, 0, 0]
+        b.limitMax=[180, 0, 0]
+    elif n.startswith("ankle_"):
+        b.lockYRot=True
+
index 27ff977..92144c0 100644 (file)
@@ -1,7 +1,38 @@
+# coding: utf-8
 import bpy
 import os
-
-
+import time
+
+###############################################################################
+# ProgressBar
+###############################################################################
+class ProgressBar(object):
+    def __init__(self, base):
+        print("#### %s ####" % base)
+        self.base=base
+        self.start=time.time() 
+        self.set('<start>', 0)
+
+    def advance(self, message, progress):
+        self.progress+=float(progress)
+        self._print(message)
+
+    def set(self, message, progress):
+        self.progress=float(progress)
+        self._print(message)
+
+    def _print(self, message):
+        print(message)
+        message="%s: %s" % (self.base, message)
+        #Blender.Window.DrawProgressBar(self.progress, message)
+
+    def finish(self):
+        self.progress=1.0
+        message='finished in %.2f sec' % (time.time()-self.start)
+        self.set(message, 1.0)
+
+
+###############################################################################
 class Writer(object):
     def __init__(self, path, encoding):
         self.io=open(path, "wb")
@@ -16,7 +47,7 @@ class Writer(object):
     def close(self):
         self.io.close()
 
-
+###############################################################################
 def createEmptyObject(scene, name):
     empty=bpy.data.objects.new(name, None)
     scene.objects.link(empty)
@@ -206,3 +237,28 @@ def materialToMqo(m):
 def faceMaterialIndex(face):
     return face.material_index
 
+def objectGetData(o):
+    return o.data
+
+def objectAddArmatureModifier(o, armature_object):
+    mod=o.modifiers.new("Modifier", "ARMATURE")
+    mod.object = armature_object
+    mod.use_bone_envelopes=False
+
+def objectSelect(o):
+    o.selected=True
+
+def objectGetPose(o):
+    return o.pose
+
+def poseBoneLimit(n, b):
+    if n.endswith("_t"):
+        return
+    if n.startswith("knee_"):
+        b.lock_rotation[1]=True
+        b.lock_rotation[2]=True
+        b.ik_min_x=0
+        b.ik_max_x=180
+    elif n.startswith("ankle_"):
+        b.lock_rotation[1]=True
+
index 10fd049..2c49f92 100644 (file)
@@ -7,9 +7,10 @@ DST_24=[
         ]
 
 MAP_25={
+        "bl25.py": "bl25.py",
         "mqo_import.py": "import_scene_mqo.py",
         "mqo_export.py": "export_scene_mqo.py",
-        "bl25.py": "bl25.py",
+        "pmd_import.py": "import_scene_pmd.py",
         }
 
 DST_25=[
diff --git a/swig/blender/pmd_import.py b/swig/blender/pmd_import.py
new file mode 100644 (file)
index 0000000..3f7220a
--- /dev/null
@@ -0,0 +1,1127 @@
+#!BPY
+# coding:utf-8
+"""
+ Name: 'MikuMikuDance model (.pmd)...'
+ Blender: 248
+ Group: 'Import'
+ Tooltip: 'Import PMD file for MikuMikuDance.'
+"""
+__author__= ["ousttrue"]
+__version__= "1.1"
+__url__=()
+__bpydoc__="""
+pmd Importer
+
+This script imports a pmd into Blender for editing.
+
+0.1: 20091126: first implement.
+0.2: 20091209: implement IK.
+0.3: 20091210: implement morph target.
+0.4: 20100305: use english name.
+0.5: 20100408: cleanup not used vertices.
+0.6: 20100416: fix fornt face. texture load fail safe. add progress.
+0.7: 20100506: C extension.
+0.8: 20100521: add shape_key group.
+1.0: 20100530: add invisilbe bone tail(armature layer 2).
+1.1: 20100608: integrate 2.4 and 2.5.
+"""
+
+MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
+
+
+###############################################################################
+# import
+###############################################################################
+import os
+import sys
+import re
+import math
+
+# C extension
+from meshio import pmd, englishmap
+
+def isBlender24():
+    return sys.version_info[0]<3
+
+if isBlender24():
+    # for 2.4
+    import Blender
+    from Blender import Mathutils
+    import bpy
+
+    # wrapper
+    import bl24 as bl
+else:
+    # for 2.5
+    import bpy
+    from bpy.props import *
+    import mathutils
+
+    # wrapper
+    import bl25 as bl
+
+
+###############################################################################
+# progress bar
+###############################################################################
+def progress_start(base):
+    global progressBar
+    progressBar=bl.ProgressBar(base)
+
+def progress_finish():
+    global progressBar
+    progressBar.finish()
+
+def progress_print(message, progress=0.05):
+    global progressBar
+    progressBar.advance(message, progress)
+
+def progress_set(message, progress):
+    global progressBar
+    progressBar.set(message, progress)
+
+
+if isBlender24():
+    # functions
+    def convert_coord(pos):
+        """
+        Left handed y-up to Right handed z-up
+        """
+        return (pos.x, pos.z, pos.y)
+
+
+    def convert_uv(uv):
+        return (uv.x, 1.0 - uv.y)
+
+
+    def get_bone_name(l, index):
+        name=englishmap.getEnglishBoneName(l.bones[index].getName())
+        return name if name else l.bones[index].getName().encode(bl.INTERNAL_ENCODING)
+
+
+    def createMaterial():
+        """
+        create default materil 
+        """
+        material=Blender.Material.New()
+        material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
+        material.setRef(1)
+        material.diffuseSize = 3.14/2
+        material.setDiffuseSmooth(0)
+        material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
+        material.setSpecSize(0)
+        material.setSpec(0)
+        return material
+
+
+    def importMesh(scene, l, tex_dir):
+        """
+        @param l[in] mmd.PMDLoader
+        @param filename[in]
+        """
+
+        ############################################################
+        # shpaeキーで使われるマテリアル優先的に前に並べる
+        ############################################################
+        # shapeキーで使われる頂点インデックスを集める
+        shape_key_used_vertices=set()
+        if len(l.morph_list)>0:
+            # base 
+            base=None
+            for s in l.morph_list:
+                if s.type!=0:
+                    continue
+                base=s
+                break
+            assert(base)
+
+            for index in base.indices:
+                shape_key_used_vertices.add(index)
+
+        # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
+        def isMaterialUsedInShape(offset, m):
+            for i in xrange(offset, offset+m.vertex_count): 
+                if l.indices[i] in shape_key_used_vertices:
+                    return True
+
+        # shapeキーで使われるマテリアルを記録する
+        shape_key_materials=set()
+        # 各マテリアルの開始頂点インデックスを記録する
+        face_map={}
+        face_count=0
+        for i, m in enumerate(l.materials):
+            face_map[i]=face_count
+            if isMaterialUsedInShape(face_count, m):
+                shape_key_materials.add(i)
+            face_count+=m.vertex_count
+
+        # list化
+        material_order=list(shape_key_materials)
+
+        # shapeキーに使われていないマテリアルを後ろに追加
+        for i in range(len(l.materials)):
+            if not i in material_order:
+                material_order.append(i)
+
+        # マテリアル16個ごとに分割したメッシュを作成する
+        material_offset=0
+        mesh_objects=[]
+        while material_offset<len(l.materials):
+            # create mesh
+            mesh = Blender.Mesh.New()
+            mesh.vertexUV = 1
+            # create object
+            obj = scene.objects.new(mesh)
+            obj.layers = [1]
+            mesh_objects.append(obj)
+
+            # shapeキーで使われる順に並べなおしたマテリアル16個分の
+            # メッシュを作成する
+            vertex_map=import16MaerialAndMesh(
+                    mesh, l, 
+                    material_order[material_offset:material_offset+16], 
+                    face_map, tex_dir)
+
+            # crete shape key
+            importShape(obj, l, vertex_map)
+
+            mesh.update()
+            material_offset+=16
+
+        return mesh_objects
+
+
+    def import16MaerialAndMesh(mesh, l, material_order, face_map, tex_dir):
+        ############################################################
+        # material
+        ############################################################
+        progress_print('create materials')
+        mesh_material_map={}
+        materials=[]
+        index=0
+        for material_index in material_order:
+            try:
+                m=l.materials[material_index]
+                mesh_material_map[material_index]=index
+            except KeyError:
+                break
+
+            material=createMaterial()
+            material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
+            material.setAlpha(m.diffuse.a)
+            material.setSpec(m.shinness*0.1)
+            material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
+            material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
+            material.enableSSS=True if m.flag==1 else False
+            # set texture
+            if m.getTexture()!='':
+                tex_file=re.compile('\*.*.spa$').sub('', m.getTexture())
+                tex_path = os.path.join(tex_dir, tex_file).encode(
+                        bl.INTERNAL_ENCODING)
+                tex = Blender.Texture.New()
+                tex.setType("Image")
+                try:
+                    tex.image = Blender.Image.Load(tex_path)
+                    material.setTexture(0, tex)
+                    material.getTextures()[0].texco = Blender.Texture.TexCo.UV
+                except IOError:
+                    print(material.name, "fail to load", tex_path)
+            materials.append(material)
+            # lookup table for assign
+            index+=1
+        mesh.materials=materials
+
+        ############################################################
+        # vertex
+        ############################################################
+        progress_print('create vertices')
+        # create vertices
+        vertex_groups={}
+        vertices=[]
+        for v in l.each_vertex():
+            vertices.append(convert_coord(v.pos))
+            vertex_groups[v.bone0]=True
+            vertex_groups[v.bone1]=True
+        mesh.verts.extend(vertices)
+
+        # create vertex group
+        for i in vertex_groups.keys():
+            mesh.addVertGroup(get_bone_name(l, i))
+
+        # vertex params
+        for i, v, mvert in zip(xrange(len(l.vertices)), l.each_vertex(), mesh.verts):
+            mvert.no=Mathutils.Vector(*convert_coord(v.normal))
+            mvert.uvco=convert_uv(v.uv)
+            w1=float(v.weight0)/100.0
+            w2=1.0-w1
+            mesh.assignVertsToGroup(get_bone_name(l, v.bone0), [i], w1, 
+                    Blender.Mesh.AssignModes.ADD)
+            mesh.assignVertsToGroup(get_bone_name(l, v.bone1), [i], w2, 
+                    Blender.Mesh.AssignModes.ADD)    
+
+        ############################################################
+        # face
+        ############################################################
+        progress_print('create faces')
+        # create faces
+        mesh_face_indices=[]
+        mesh_face_materials=[]
+        used_vertices=set()
+
+        def degenerate(i0, i1, i2):
+            return i0==i1 or i1==i2 or i2==i0
+
+        for material_index in material_order:
+            face_offset=face_map[material_index]
+            m=l.materials[material_index]
+            material_faces=l.indices[face_offset:face_offset+m.vertex_count]
+            for j in xrange(0, len(material_faces), 3):
+                i0=material_faces[j]
+                i1=material_faces[j+1]
+                i2=material_faces[j+2]
+                triangle=[i0, i1, i2]
+                if degenerate(*triangle):
+                    continue
+                mesh_face_indices.append(triangle)
+                mesh_face_materials.append(material_index)
+                used_vertices.add(i0)
+                used_vertices.add(i1)
+                used_vertices.add(i2)
+
+        mesh.faces.extend(mesh_face_indices, ignoreDups=True)
+
+        # face params
+        used_map={}
+        mesh.addUVLayer('NewUV')
+        for face, material_index in zip(mesh.faces, mesh_face_materials):
+            try:
+                index=mesh_material_map[material_index]
+            except KeyError as message:
+                print(message, mesh_material_map, m)
+                assert(False)
+            face.mat=index
+            material=mesh.materials[index]
+            texture=material.getTextures()[0]
+            used_map[index]=True
+            if texture:
+                face.image=texture.tex.image
+                texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
+                face.uv=[face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
+            # set smooth
+            face.smooth = 1
+        # flip
+        mesh.flipNormals()
+
+        ############################################################
+        # clean up not used vertices
+        ############################################################
+        progress_print('clean up vertices not used')
+        remove_vertices=[]
+        vertex_map={}
+        for i, v in enumerate(l.each_vertex()):
+            if i in used_vertices:
+                vertex_map[i]=len(vertex_map)
+            else:
+                remove_vertices.append(i)
+        mesh.verts.delete(remove_vertices)
+
+        progress_print('%s created' % mesh.name)
+        return vertex_map
+
+
+    class Builder(object):
+        def __init__(self):
+            self.boneMap={}
+
+        def build(self, armature, bones):
+            for b in bones:
+                if not b.parent:
+                    self.__build(armature, b, None, None)
+            armature.update()
+
+        def __build(self, armature, b, p, parent):
+            name=englishmap.getEnglishBoneName(b.getName())
+            if not name:
+                name=b.getName().encode(bl.INTERNAL_ENCODING)
+            self.boneMap[name]=b
+
+            bone=Blender.Armature.Editbone()
+            bone.name=name
+            armature.bones[name]=bone
+
+            if b.tail_index==0:
+                # 先端
+                assert(b.type==6 or b.type==7)
+                bone.head = Mathutils.Vector(*convert_coord(b.pos))
+                bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
+                assert(parent)
+                bone.parent=parent
+                if bone.name=="center_t":
+                    # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
+                    parent.tail=parent.head+Mathutils.Vector(0, 1, 0)
+                    bone.head=parent.tail
+                    bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
+                else:
+                    assert(parent.tail==bone.head)
+                bone.options=[Blender.Armature.CONNECTED]
+                # armature layer 2
+                bone.layerMask = (1<<1)
+            else:
+                bone.head = Mathutils.Vector(*convert_coord(b.pos))
+                bone.tail = Mathutils.Vector(*convert_coord(b.tail))
+                if parent:
+                    bone.parent=parent
+                    if parent.tail==bone.head:
+                        bone.options=[Blender.Armature.CONNECTED]
+
+            if bone.head==bone.tail:
+                bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
+
+            for c in b.children:
+                self.__build(armature, c, b, bone)
+
+
+    def importArmature(scene, l):
+        # create armature
+        armature = Blender.Armature.New()
+        # link to object
+        armature_object = scene.objects.new(armature)
+        # create action
+        act = Blender.Armature.NLA.NewAction()
+        act.setActive(armature_object)
+        # set XRAY
+        armature_object.drawMode = (
+                armature_object.drawMode | Blender.Object.DrawModes.XRAY)
+        # armature settings
+        armature.drawType = Blender.Armature.OCTAHEDRON
+        armature.drawNames=True
+        armature.envelopes = False
+        armature.vertexGroups = True
+        armature.mirrorEdit = True
+
+        # create armature
+        armature.makeEditable()
+
+        ############################################################
+        # build bone
+        ############################################################
+        builder=Builder()
+        builder.build(armature, l.bones)
+
+        ############################################################
+        # IK
+        ############################################################
+        pose = armature_object.getPose()
+        cSetting = Blender.Constraint.Settings
+        for ik in l.ik_list:
+            # IKtarget->parent(=IK).name
+            target=l.bones[ik.target]
+            name = englishmap.getEnglishBoneName(target.getName())
+            p_bone = pose.bones[name]
+            if not p_bone:
+                print('not found', name)
+                continue
+            if len(ik.children) >= 16:
+                print('over MAX_CHAINLEN', ik, len(ik.children))
+                continue
+            # IK solver
+            ik_solver = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
+            ik_solver[cSetting.CHAINLEN]=len(ik.children)
+            ik_solver[cSetting.TARGET]=armature_object
+            ik_solver[cSetting.USETIP]=False
+
+            effector_name=englishmap.getEnglishBoneName(
+                    l.bones[ik.index].getName())
+            if not effector_name:
+                effector_name=l.bones[ik.index].getName()
+
+            ik_solver[cSetting.BONE]=effector_name
+            #ik_solver.influence=ik.weight
+            # not used. place folder when export.
+            ik_solver[cSetting.ROTWEIGHT]=ik.weight
+            ik_solver[cSetting.ITERATIONS]=ik.iterations * 10
+
+        armature.makeEditable()
+        armature.update()
+
+        return armature_object
+        
+
+    def importShape(obj, l, vertex_map):
+        if len(l.morph_list)==0:
+            return
+        obj.pinShape=True
+        mesh=obj.getData(mesh=True)
+
+        # find base 
+        base=None
+        for s in l.morph_list:
+            if s.type==0:
+                base=s
+
+                # create vertex group
+                mesh.addVertGroup(MMD_SHAPE_GROUP_NAME)
+                indices=[]
+                hasShape=False
+                for i in s.indices:
+                    if i in vertex_map:
+                        hasShape=True
+                        indices.append(vertex_map[i])
+                mesh.assignVertsToGroup(MMD_SHAPE_GROUP_NAME, indices, 0, 
+                        Blender.Mesh.AssignModes.ADD)
+                if not hasShape:
+                    return
+
+                # create base key
+                mesh.insertKey()
+                assert(len(mesh.key.blocks)==1)
+                baseShapeIndex=0
+                baseShapeBlock=mesh.key.blocks[baseShapeIndex]
+                baseShapeBlock.name='Basis'
+                obj.activeShape=baseShapeIndex
+                mesh.update()
+                break
+
+        assert(base)
+
+        # each skin
+        for s in l.morph_list:
+            if s.name==base.name:
+                continue
+
+            for index, offset in zip(s.indices, s.pos_list):
+                try:
+                    vertex_index=vertex_map[base.indices[index]]
+                    v=mesh.verts[vertex_index].co
+                    offset=convert_coord(offset)
+                    v[0]+=offset[0]
+                    v[1]+=offset[1]
+                    v[2]+=offset[2]
+                except IndexErrora as msg:
+                    print(msg)
+                    print(index, len(base.indices), len(vertex_map))
+                    print(len(mesh.verts))
+                    print(base.indices[index])
+                    print(vertex_index)
+                    break
+                except KeyError:
+                    #print 'this mesh not has shape vertices'
+                    break
+
+            # get skin name
+            name=englishmap.getEnglishSkinName(s.getName())
+            if not name:
+                name=s.getName().encode(bl.INTERNAL_ENCODING)
+                print(name)
+
+            # create shapekey block
+            mesh.insertKey()
+            shapeIndex=len(mesh.key.blocks)-1
+            keyBlock=mesh.key.blocks[shapeIndex]
+            keyBlock.name=name
+
+            # copy vertex to shape key
+            mesh.update()
+            
+            # restore
+            for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
+                mv.co[0] = v[0]
+                mv.co[1] = v[1]
+                mv.co[2] = v[2]
+            mesh.update()
+
+        # select base shape
+        obj.activeShape=baseShapeIndex
+
+else:
+    # for 2.5
+    def to_radian(degree):
+        return math.pi * degree / 180
+
+
+    def convert_coord(pos):
+        """
+        Left handed y-up to Right handed z-up
+        """
+        return (pos.x, pos.z, pos.y)
+
+
+    def convert_uv(uv):
+        return (uv.x, 1.0 - uv.y)
+
+
+    def getBoneName(bone):
+        name = englishmap.getEnglishBoneName(bone.getName())
+        return name if name else bone.getName()
+
+
+    def create_texture(directory, texture_name):
+        texture=bpy.data.textures.new(texture_name)
+        texture.type='IMAGE'
+        texture=texture.recast_type()
+        texturePath=os.path.join(directory, texture_name)
+        print('create_texture', texturePath)
+        image=bpy.data.images.load(texturePath)
+        texture.image=image
+        texture.mipmap = True
+        texture.interpolation = True
+        texture.use_alpha = True
+        return texture
+
+
+    def createMaterial():
+        """
+        create default materil 
+        """
+        material = bpy.data.materials.new("Material")
+        material.diffuse_shader='TOON'
+        material.specular_shader='TOON'
+        # temporary
+        material.emit=1.0
+        return material
+
+
+    def importMesh(scene, l, tex_dir):
+        """
+        @param l[in] mmd.PMDLoader
+        @param filename[in]
+        """
+
+        ############################################################
+        # shpaeキーで使われるマテリアル優先的に前に並べる
+        ############################################################
+        # shapeキーで使われる頂点インデックスを集める
+        shape_key_used_vertices=set()
+        if len(l.morph_list)>0:
+            # base 
+            base=None
+            for s in l.morph_list:
+                if s.type!=0:
+                    continue
+                base=s
+                break
+            assert(base)
+
+            for index in base.indices:
+                shape_key_used_vertices.add(index)
+
+        # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
+        def isMaterialUsedInShape(offset, m):
+            for i in range(offset, offset+m.vertex_count): 
+                if l.indices[i] in shape_key_used_vertices:
+                    return True
+
+        # shapeキーで使われるマテリアルを記録する
+        shape_key_materials=set()
+        # 各マテリアルの開始頂点インデックスを記録する
+        face_map={}
+        face_count=0
+        for i, m in enumerate(l.materials):
+            face_map[i]=face_count
+            if isMaterialUsedInShape(face_count, m):
+                shape_key_materials.add(i)
+            face_count+=m.vertex_count
+
+        # shapeキーで使われるマテリアルを前に並べるインデックスマップを作る
+        material_map={}
+        used_index=0
+        not_used_index=len(shape_key_materials)
+        for i, m in enumerate(l.materials):
+            if i in shape_key_materials:
+                material_map[i]=used_index
+                used_index+=1
+            else:
+                material_map[i]=not_used_index
+                not_used_index+=1
+
+        # マテリアル16個ごとに分割したメッシュを作成する
+        material_index=0
+        mesh_objects=[]
+        while material_index<len(l.materials):
+            # shapeキーで使われる順に並べなおしたマテリアル16個分の
+            # メッシュを作成する
+            meshObject, used_vertices=import16MaerialAndMesh(l, 
+                    material_index, material_map, face_map, tex_dir)
+            scene.objects.link(meshObject)
+            scene.update()
+            mesh_objects.append(meshObject)
+
+            # enter Edit Mode
+            bpy.ops.object.select_all(action='DESELECT')
+            meshObject.selected=True
+            scene.objects.active=meshObject
+            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+     
+            # crete shape key
+            importShape(meshObject, l)
+
+            ############################################################
+            # clean up not used vertices
+            ############################################################
+            #progress_print('clean up vertices not used')
+            vertex_map={}
+            mesh=meshObject.data
+            for i, v in enumerate(mesh.verts):
+                if i in used_vertices:
+                    vertex_map[i]=len(vertex_map)
+                    v.selected=False
+                else:
+                    v.selected=True
+                    assert(mesh.verts[i].selected)
+            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+            print("%d vertices selected" % mesh.total_vert_sel)
+            print("used %d/%d" % (len(vertex_map), len(mesh.verts)))
+            bpy.ops.mesh.delete(type='VERT')
+
+            ############################################################
+            # flip face
+            ############################################################
+            bpy.ops.mesh.select_all(action='SELECT')
+            bpy.ops.mesh.flip_normals()
+            bpy.ops.mesh.select_all(action='DESELECT')
+
+            # exit Edit Mode
+            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+            mesh.update()
+            material_index+=16
+
+        return mesh_objects
+
+
+    def import16MaerialAndMesh(l, 
+            material_offset, material_map, face_map, tex_dir):
+        # create mesh
+        mesh=bpy.data.meshes.new("Mesh")
+
+        # create object
+        meshObject= bpy.data.objects.new("Mesh", mesh)
+        meshObject.layers[0]=True
+
+        ############################################################
+        # material
+        ############################################################
+        #progress_print('create materials')
+        mesh_material_map={}
+        materials=[]
+        textureMap={}
+        imageMap={}
+        index=0
+        for i in range(material_offset, material_offset+16):
+            try:
+                material_index=material_map[i]
+                m=l.materials[material_index]
+                mesh_material_map[material_index]=index
+            except KeyError:
+                break
+
+            material=createMaterial()
+            material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
+            material.alpha=m.diffuse.a
+            material.specular_hardness=int(m.shinness)
+            material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
+            material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
+            texture_name=m.getTexture()
+            if texture_name!='':
+                if texture_name in textureMap:
+                    texture=textureMap[texture_name]
+                else:
+                    texture=create_texture(tex_dir, texture_name)
+                    textureMap[texture_name]=texture
+                    imageMap[material_index]=texture.image
+                #material.add_texture(texture, "UV", {"COLOR", "ALPHA"})
+                material.add_texture(texture, "UV", "COLOR")
+
+            materials.append(material)
+            mesh.add_material(material)
+            # lookup table for assign
+            index+=1
+
+        ############################################################
+        # vertex
+        ############################################################
+        #progress_print('create vertices')
+        # create vertices
+        vertex_groups={}
+        unpackedVertices=[]
+        for v in l.each_vertex():
+            unpackedVertices.extend(
+                    convert_coord(v.pos))
+            vertex_groups[v.bone0]=True
+            vertex_groups[v.bone1]=True
+
+        ############################################################
+        # face
+        ############################################################
+        #progress_print('create faces')
+        # create faces
+        mesh_face_indices=[]
+        mesh_face_materials=[]
+        used_vertices=set()
+        for i in range(material_offset, material_offset+16):
+            try:
+                material_index=material_map[i]
+            except KeyError:
+                break
+            face_offset=face_map[material_index]
+            m=l.materials[material_index]
+            material_faces=l.indices[face_offset:face_offset+m.vertex_count]
+            for j in range(0, len(material_faces), 3):
+                i0=material_faces[j]
+                i1=material_faces[j+1]
+                i2=material_faces[j+2]
+                if i2==0:
+                    mesh_face_indices.extend([i2, i0, i1, 0])
+                else:
+                    mesh_face_indices.extend([i0, i1, i2, 0])
+                mesh_face_materials.append(material_index)
+                used_vertices.add(i0)
+                used_vertices.add(i1)
+                used_vertices.add(i2)
+
+        ############################################################
+        # create vertices & faces
+        ############################################################
+        mesh.add_geometry(
+                int(len(unpackedVertices)/3), 0, int(len(mesh_face_indices)/4))
+        mesh.verts.foreach_set("co", unpackedVertices)
+        mesh.faces.foreach_set("verts_raw", mesh_face_indices)
+        assert(len(l.vertices)==len(mesh.verts))
+
+        ############################################################
+        # face params
+        ############################################################
+        used_map={}
+        mesh.add_uv_texture()
+
+        for face, uv_face, material_index in zip(mesh.faces, 
+                mesh.uv_textures[0].data,
+                mesh_face_materials,
+                ):
+            try:
+                index=mesh_material_map[material_index]
+            except KeyError as message:
+                print(message, mesh_material_map, m)
+                assert(False)
+            face.material_index=index
+            material=mesh.materials[index]
+            used_map[index]=True
+            if material.texture_slots[0]:
+                #texture=material.texture_slots[0].texture
+                #face.image=texture.image
+                #texture.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
+                uv=l.getUV(face.verts[0])
+                uv_face.uv1=[uv.x, 1.0-uv.y]
+
+                uv=l.getUV(face.verts[1])
+                uv_face.uv2=[uv.x, 1.0-uv.y]
+
+                uv=l.getUV(face.verts[2])
+                uv_face.uv3=[uv.x, 1.0-uv.y]
+            if face.material_index in imageMap:
+                uv_face.image=imageMap[face.material_index]
+                uv_face.tex=True
+
+            # set smooth
+            face.smooth = 1
+
+        ############################################################
+        # vertex weight
+        ############################################################
+        # create vertex group
+        for i in vertex_groups.keys():
+            meshObject.add_vertex_group(getBoneName(l.bones[i]))
+
+        # vertex params
+        for i, v, mvert in zip(range(len(l.vertices)), 
+                l.each_vertex(), mesh.verts):
+            mvert.normal=mathutils.Vector(convert_coord(v.normal))
+            #mvert.uvco=convert_uv(v.uv)
+            w1=float(v.weight0)/100.0
+            w2=1.0-w1
+
+            meshObject.add_vertex_to_group(i, 
+                    meshObject.vertex_groups[getBoneName(l.bones[v.bone0])], w1, 'ADD')
+            meshObject.add_vertex_to_group(i, 
+                    meshObject.vertex_groups[getBoneName(l.bones[v.bone1])], w2, 'ADD')
+        mesh.update()
+
+        #progress_print('%s created' % mesh.name)
+        return meshObject, used_vertices
+
+
+    def build_bone(armature, b, parent=None):
+        if b.tail_index==0:
+            return
+
+        name=getBoneName(b)
+        bone = armature.edit_bones.new(name if name else b.getName())
+        if parent:
+            bone.head = mathutils.Vector(convert_coord(b.pos))
+            bone.parent=parent
+            bone.connected=True if parent.tail==bone.head else False
+            bone.tail = mathutils.Vector(convert_coord(b.tail))
+            if bone.head==bone.tail:
+                bone.tail=bone.head-mathutils.Vector((0, 1, 0))
+        elif b.__class__ is pmd.BONE_IK:
+            bone.head = mathutils.Vector(convert_coord(b.pos))
+            bone.tail = mathutils.Vector(convert_coord(b.tail))
+        else:
+            # center
+            tail=mathutils.Vector(convert_coord(b.pos))
+            bone.tail = tail
+            bone.head = tail-mathutils.Vector((0, 1, 0))
+
+        for child in b.children:
+            build_bone(armature, child, bone)
+
+
+    def importArmature(scene, l):
+        # create armature
+        armature = bpy.data.armatures.new('Armature')
+        # link to object
+        armature_object=bpy.data.objects.new('Armature', armature)
+        scene.objects.link(armature_object)
+        armature_object.x_ray=True
+        armature.draw_names=True
+
+        # armature settings
+        armature.drawtype='OCTAHEDRAL'
+        armature.deform_envelope=False
+        armature.deform_vertexgroups=True
+        armature.x_axis_mirror=True
+
+        # create action
+        #act = Blender.Armature.NLA.NewAction()
+        #act.setActive(armature_object)
+
+        # select only armature object and set edit mode
+        scene.objects.active=armature_object
+        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+
+        # create armature
+        for b in l.bones:
+            if not b.parent:
+                build_bone(armature, b)
+
+        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+        bpy.ops.object.select_all(action='DESELECT')
+
+        ############################################################
+        # IK
+        ############################################################
+        pose = armature_object.pose
+        for ik in l.ik_list:
+            effector=l.bones[ik.target]
+            parent=l.bones[effector.parent_index]
+            name=getBoneName(parent)
+            p_bone = pose.bones[name]
+            if not p_bone:
+                print('not found', name)
+                continue
+            if len(ik.children) >= 16:
+                print('over MAX_CHAINLEN', ik, len(ik.children))
+                continue
+            # IK
+            ik_const = p_bone.constraints.new('IK')
+            ik_const.chain_length=len(ik.children)
+            ik_const.target=armature_object
+            ik_const.subtarget=getBoneName(l.bones[ik.index])
+            # ROT
+            rot_const = p_bone.constraints.new('LIMIT_ROTATION')
+            rot_const.influence = ik.weight
+            rot_const.owner_space = 'LOCAL'
+            rot_const.use_limit_x=True
+            rot_const.use_limit_z=True
+            rot_const.minimum_x=to_radian(ik.iterations)
+            rot_const.maximum_x=to_radian(180)
+            rot_const.minimum_z=to_radian(180 - ik.iterations)
+            rot_const.maximum_z=to_radian(0)
+
+        return armature_object
+        
+
+    def importShape(meshObject, l):
+        if len(l.morph_list)==0:
+            return
+
+        # base 
+        base=None
+        for s in l.morph_list:
+            if s.type!=0:
+                continue
+            base=s
+            break
+        assert(base)
+
+        # create base key
+        baseblock=meshObject.add_shape_key("Basis")
+
+        # mesh
+        mesh=meshObject.data
+
+        # each skin
+        for s in l.morph_list:
+            if s.getName()==base.name:
+                # skip base
+                continue
+
+            # restore
+            #for v, base_pos in zip(mesh.verts, baseblock.data):
+            #    v.co=base_pos.co
+            #mesh.update()
+
+            # name
+            name=englishmap.getEnglishSkinName(s.getName())
+            if not name:
+                name=s.getName()
+            new_shape_key=meshObject.add_shape_key(name)
+            #new_shape_key.value=1.0
+
+            # morph
+            for i, offset in zip(s.indices, s.pos_list):
+                try:
+                    vertex_index=base.indices[i]
+                    new_shape_key.data[vertex_index].co=[p+o for p, o in zip(
+                        mesh.verts[vertex_index].co, convert_coord(offset))]
+                except IndexError as msg:
+                    print(IndexError, msg)
+                    print(i, len(base.indices))
+                    print(vertex_index, len(mesh.verts))
+                    print(base.indices[i])
+                    break
+                except KeyError:
+                    #print 'this mesh not has shape vertices'
+                    break
+            
+            # set ipo curve
+            #icu=ipo.addCurve(name)
+            #icu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
+            #icu.append( (0.0, 0.0) )
+
+   
+def __execute(filename, scene):
+    """
+    load pmd file to context.
+    """
+    # load pmd
+    progress_set('load %s' % filename, 0.0)
+
+    io=pmd.IO()
+    if not io.read(filename):
+        print("fail to load %s" % filename)
+        return
+    progress_set('loaded %s' % filename, 0.1)
+
+    # create root object
+    root=bl.createEmptyObject(scene, 
+            io.english_name if len(io.english_name)>0 else io.getName().encode(bl.INTERNAL_ENCODING))
+
+    # import mesh
+    mesh_objects=importMesh(scene, io, os.path.dirname(filename))
+    for o in mesh_objects:
+        bl.objectMakeParent(root, o)
+
+    # import armature
+    armature_object=importArmature(scene, io)
+    if armature_object:
+        bl.objectMakeParent(root, armature_object)
+        armature = bl.objectGetData(armature_object) 
+
+        # add armature modifier
+        for o in mesh_objects:
+            bl.objectAddArmatureModifier(o, armature_object)
+
+        # Limitation
+        for n, b in bl.objectGetPose(armature_object).bones.items():
+            bl.poseBoneLimit(n, b)
+
+    # select objects
+    bl.objectSelect(root)
+    for o in mesh_objects:
+        bl.objectSelect(o)
+    bl.objectSelect(armature_object)
+
+if isBlender24():
+    # for 2.4
+    def execute_24(filename):
+        """
+        @param filename
+        """
+        filename=filename.decode(bl.INTERNAL_ENCODING)
+        print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
+
+        # set object mode
+        mode_edit = Blender.Window.EditMode() 
+        if mode_edit: 
+            Blender.Window.EditMode(0)
+            
+        progress_start('pmd_import')
+        scene = bpy.data.scenes.active
+        __execute(filename, scene)
+        scene.update(0)
+        progress_finish()
+
+        # restore edit mode
+        if mode_edit: 
+            Blender.Window.EditMode(1)
+        Blender.Window.RedrawAll()
+
+    Blender.Window.FileSelector(
+            execute_24, 
+            'Import PMD file', 
+            Blender.sys.makename(ext='.pmd'))
+
+else:
+    # for 2.5
+    def execute_25(*args):
+        progress_start('pmd_import')
+        __execute(*args)
+        progress_finish()
+
+    # import operator
+    class IMPORT_OT_pmd(bpy.types.Operator):
+        bl_idname = "import_scene.pmd"
+        bl_label = 'Import PMD'
+
+        # List of operator properties, the attributes will be assigned
+        # to the class instance from the operator settings before calling.
+
+        path = StringProperty(
+                name="File Path", 
+                description="File path used for importing the PMD file", 
+                maxlen= 1024, default= "")
+        filename = StringProperty(
+                name="File Name", 
+                description="Name of the file.")
+        directory = StringProperty(
+                name="Directory", 
+                description="Directory of the file.")
+
+        def execute(self, context):
+            execute_25(self.properties.path, context.scene)
+            return 'FINISHED'
+
+        def invoke(self, context, event):
+            wm = context.manager
+            wm.add_fileselect(self)
+            return 'RUNNING_MODAL'
+
+    # register menu
+    def menu_func(self, context): 
+        self.layout.operator(IMPORT_OT_pmd.bl_idname, 
+                text="MikuMikuDance model (.pmd)")
+
+    def register():
+        bpy.types.register(IMPORT_OT_pmd)
+        bpy.types.INFO_MT_file_import.append(menu_func)
+
+    def unregister():
+        bpy.types.unregister(IMPORT_OT_pmd)
+        bpy.types.INFO_MT_file_import.remove(menu_func)
+
+    if __name__=="__main__":
+        register()
+