OSDN Git Service

import from old repository
authorU-theremin\focke <ousttrue@gmail.com>
Fri, 29 Apr 2011 09:28:14 +0000 (18:28 +0900)
committerU-theremin\focke <ousttrue@gmail.com>
Fri, 29 Apr 2011 09:28:14 +0000 (18:28 +0900)
pymeshio/bl25.py [new file with mode: 0755]
pymeshio/io_export_scene_mqo.py [new file with mode: 0755]
pymeshio/io_export_scene_pmd.py [new file with mode: 0755]
pymeshio/io_import_scene_mqo.py [new file with mode: 0755]
pymeshio/io_import_scene_pmd.py [new file with mode: 0755]
pymeshio/pymeshio/__init__.py [new file with mode: 0755]
pymeshio/pymeshio/englishmap.py [new file with mode: 0755]
pymeshio/pymeshio/mmd.py [new file with mode: 0755]
pymeshio/pymeshio/mqo.py [new file with mode: 0755]

diff --git a/pymeshio/bl25.py b/pymeshio/bl25.py
new file mode 100755 (executable)
index 0000000..eaec64f
--- /dev/null
@@ -0,0 +1,651 @@
+# coding: utf-8
+import os
+import sys
+import time
+import functools
+
+try:
+    import bpy
+    import mathutils
+except:
+    pass
+
+FS_ENCODING=sys.getfilesystemencoding()
+if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
+    INTERNAL_ENCODING='utf-8'
+else:
+    INTERNAL_ENCODING=FS_ENCODING
+
+def register():
+    pass
+
+def unregister():
+    pass
+
+SCENE=None
+def initialize(name, scene):
+    global SCENE
+    SCENE=scene
+    progress_start(name)
+
+def finalize():
+    scene.update(SCENE)
+    progress_finish()
+
+def message(msg):
+    print(msg)
+
+def enterEditMode():
+    bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+
+def enterObjectMode():
+    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+def enterPoseMode():
+    bpy.ops.object.mode_set(mode='POSE', toggle=False)
+
+def createVector(x, y, z):
+    return mathutils.Vector([x, y, z])
+
+
+class Writer(object):
+    '''
+    io wrapper
+    '''
+    def __init__(self, path, encoding):
+        self.io=open(path, "wb")
+        self.encoding=encoding
+
+    def write(self, s):
+        self.io.write(s.encode(self.encoding))
+
+    def flush(self):
+        self.io.flush()
+
+    def close(self):
+        self.io.close()
+
+
+class ProgressBar(object):
+    '''
+    progress bar wrapper
+    '''
+    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)
+
+def progress_start(base):
+    global progressBar
+    progressBar=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)
+
+
+class scene:
+    @staticmethod
+    def update(scene):
+        scene.update()
+
+
+class object:
+    @staticmethod
+    def createEmpty(name):
+        global SCENE
+        empty=bpy.data.objects.new(name, None)
+        SCENE.objects.link(empty)
+        return empty
+
+    @staticmethod
+    def each():
+        for o in SCENE.objects:
+            yield o
+
+    @staticmethod
+    def makeParent(parent, child):
+        child.parent=parent
+
+    @staticmethod
+    def duplicate(o):
+        global SCENE
+        bpy.ops.object.select_all(action='DESELECT')
+        o.select=True
+        SCENE.objects.active=o
+        bpy.ops.object.duplicate()
+        dumy=SCENE.objects.active
+        #bpy.ops.object.rotation_apply()
+        #bpy.ops.object.scale_apply()
+        #bpy.ops.object.location_apply()
+        return dumy.data, dumy
+
+    @staticmethod
+    def delete(o):
+        global SCENE
+        SCENE.objects.unlink(o)
+
+    @staticmethod
+    def getData(o):
+        return o.data
+
+    @staticmethod
+    def select(o):
+        o.select=True
+
+    @staticmethod
+    def activate(o):
+        global SCENE
+        o.select=True 
+        SCENE.objects.active=o
+
+    @staticmethod
+    def getActive():
+        global SCENE 
+        return SCENE.objects.active
+
+    @staticmethod
+    def deselectAll():
+        bpy.ops.object.select_all(action='DESELECT')
+
+    @staticmethod
+    def setLayerMask(object, layers):
+        layer=[]
+        for i in range(20):
+            try:
+                layer.append(True if layers[i]!=0 else False)
+            except IndexError:
+                layer.append(False)
+        object.layers=layer
+
+    @staticmethod
+    def isVisible(o):
+        return False if o.hide else True
+
+    @staticmethod
+    def getShapeKeys(o):
+        return o.data.shape_keys.keys
+
+    @staticmethod
+    def addShapeKey(o, name):
+        try:
+            return o.shape_key_add(name)
+        except:
+            return o.add_shape_key(name)
+
+    @staticmethod
+    def hasShapeKey(o):
+        return o.data.shape_keys
+
+    @staticmethod
+    def pinShape(o, enable):
+        o.show_only_shape_key=enable
+
+    @staticmethod
+    def setActivateShapeKey(o, index):
+        o.active_shape_key_index=index
+
+    @staticmethod
+    def getPose(o):
+        return o.pose
+
+    @staticmethod
+    def getVertexGroup(o, name):
+        indices=[]
+        for i, v in enumerate(o.data.vertices):
+            for g in v.groups:
+                if o.vertex_groups[g.group].name==name:
+                    indices.append(i)
+        return indices
+
+    @staticmethod
+    def getVertexGroupNames(o):
+        for g in o.vertex_groups:
+            yield g.name
+
+    @staticmethod
+    def addVertexGroup(o, name):
+        o.vertex_groups.new(name)
+
+    @staticmethod
+    def assignVertexGroup(o, name, index, weight):
+        g=o.vertex_groups[name]
+        o.vertex_groups.assign([index], g, weight, 'ADD')
+
+    @staticmethod
+    def createBoneGroup(o, name, color_set='DEFAULT'):
+        # create group
+        object.activate(o)
+        enterPoseMode()
+        bpy.ops.pose.group_add()
+        # set name
+        pose=object.getPose(o)
+        g=pose.bone_groups.active
+        g.name=name
+        g.color_set=color_set
+
+    @staticmethod
+    def boneGroups(o):
+        return object.getPose(o).bone_groups
+
+
+class modifier:
+    @staticmethod
+    def addMirror(mesh_object):
+        return mesh_object.modifiers.new("Modifier", "MIRROR")
+
+    @staticmethod
+    def addArmature(mesh_object, armature_object):
+        mod=mesh_object.modifiers.new("Modifier", "ARMATURE")
+        mod.object = armature_object
+        mod.use_bone_envelopes=False
+
+    @staticmethod
+    def hasType(mesh_object, type_name):
+        for mod in mesh_object.modifiers:
+                if mod.type==type_name.upper():
+                    return True
+
+    @staticmethod
+    def isType(m, type_name):
+        return m.type==type_name.upper()
+
+    @staticmethod
+    def getArmatureObject(m):
+        return m.object
+
+
+class shapekey:
+    @staticmethod
+    def assign(shapeKey, index, pos):
+        shapeKey.data[index].co=pos
+
+    @staticmethod
+    def getByIndex(b, index):
+        return b.data[index].co
+
+    @staticmethod
+    def get(b):
+        for k in b.data:
+            yield k.co
+
+
+class texture:
+    @staticmethod
+    def create(path):
+        texture=bpy.data.textures.new(os.path.basename(path), 'IMAGE')
+        texture.use_mipmap=True
+        texture.use_interpolation=True
+        texture.use_alpha=True
+        try:
+            image=bpy.data.images.load(path)
+        except SystemError:
+            image=bpy.data.images.new('Image')
+        texture.image=image
+        return texture, image
+
+    @staticmethod
+    def getPath(t):
+        if  t.type=="IMAGE":
+            image=t.image
+            if image:
+                return image.filepath
+
+
+class material:
+    @staticmethod
+    def create(name):
+        return bpy.data.materials.new(name)
+
+    @staticmethod
+    def get(material_name):
+        return bpy.data.materials[material_name]
+
+    @staticmethod
+    def addTexture(material, texture, enable=True):
+        # search free slot
+        index=None
+        for i, slot in enumerate(material.texture_slots):
+            if not slot:
+                index=i
+                break
+        if index==None:
+            return
+        #
+        #material.add_texture(texture, "UV", "COLOR")
+        #slot=material.texture_slots.add()
+        slot=material.texture_slots.create(index)
+        slot.texture=texture
+        slot.texture_coords='UV'
+        slot.blend_type='MULTIPLY'
+        slot.use_map_alpha=True
+        slot.use=enable
+        return index
+
+    @staticmethod
+    def getTexture(m, index):
+        return m.texture_slots[index].texture
+
+    @staticmethod
+    def hasTexture(m):
+        return m.texture_slots[0]
+
+    @staticmethod
+    def setUseTexture(m, index, enable):
+        m.use_textures[index]=enable
+
+    @staticmethod
+    def eachTexturePath(m):
+        for slot in m.texture_slots:
+            if slot and slot.texture:
+                texture=slot.texture
+                if  texture.type=="IMAGE":
+                    image=texture.image
+                    if not image:
+                        continue
+                    yield image.filepath
+
+    @staticmethod
+    def eachEnalbeTexturePath(m):
+        for i, slot in enumerate(m.texture_slots):
+            if m.use_textures[i] and slot and slot.texture:
+                texture=slot.texture
+                if  texture.type=="IMAGE":
+                    image=texture.image
+                    if not image:
+                        continue
+                    yield image.filepath
+
+
+class mesh:
+    @staticmethod
+    def create(name):
+        global SCENE
+        mesh=bpy.data.meshes.new("Mesh")
+        mesh_object= bpy.data.objects.new(name, mesh)
+        SCENE.objects.link(mesh_object)
+        return mesh, mesh_object
+
+    @staticmethod
+    def addGeometry(mesh, vertices, faces):
+        mesh.from_pydata(vertices, [], faces)
+        """
+        mesh.add_geometry(len(vertices), 0, len(faces))
+        # add vertex
+        unpackedVertices=[]
+        for v in vertices:
+            unpackedVertices.extend(v)
+        mesh.vertices.foreach_set("co", unpackedVertices)
+        # add face
+        unpackedFaces = []
+        for face in faces:
+            if len(face) == 4:
+                if face[3] == 0:
+                    # rotate indices if the 4th is 0
+                    face = [face[3], face[0], face[1], face[2]]
+            elif len(face) == 3:
+                if face[2] == 0:
+                    # rotate indices if the 3rd is 0
+                    face = [face[2], face[0], face[1], 0]
+                else:
+                    face.append(0)
+            unpackedFaces.extend(face)
+        mesh.faces.foreach_set("verts_raw", unpackedFaces)
+        """
+        assert(len(vertices)==len(mesh.vertices))
+        assert(len(faces)==len(mesh.faces))
+
+    @staticmethod
+    def hasUV(mesh):
+        return mesh.active_uv_texture
+
+    @staticmethod
+    def useVertexUV(mesh):
+        pass
+
+    @staticmethod
+    def addUV(mesh):
+        mesh.uv_textures.new()
+
+    @staticmethod
+    def hasFaceUV(mesh, i, face):
+        return mesh.active_uv_texture and mesh.active_uv_texture.data[i]
+
+    @staticmethod
+    def getFaceUV(mesh, i, faces, count=3):
+        if mesh.active_uv_texture and mesh.active_uv_texture.data[i]:
+            uvFace=mesh.active_uv_texture.data[i]
+            if count==3:
+                return (uvFace.uv1, uvFace.uv2, uvFace.uv3)
+            elif count==4:
+                return (uvFace.uv1, uvFace.uv2, uvFace.uv3, uvFace.uv4)
+            else:
+                print(count)
+                assert(False)
+        else:
+            return ((0, 0), (0, 0), (0, 0), (0, 0))
+
+    @staticmethod
+    def setFaceUV(m, i, face, uv_array, image):
+        uv_face=m.uv_textures[0].data[i]
+        uv_face.uv=uv_array
+        if image:
+            uv_face.image=image
+            uv_face.use_image=True
+
+    @staticmethod
+    def vertsDelete(m, remove_vertices):
+        enterEditMode()
+        bpy.ops.mesh.select_all(action='DESELECT')
+        enterObjectMode()
+
+        for i in remove_vertices:
+            m.vertices[i].select=True
+
+        enterEditMode()
+        bpy.ops.mesh.delete(type='VERT')
+        enterObjectMode()
+
+    @staticmethod
+    def setSmooth(m, smoothing):
+        m.auto_smooth_angle=int(smoothing)
+        m.use_auto_smooth=True
+
+    @staticmethod
+    def recalcNormals(mesh_object):
+        bpy.ops.object.select_all(action='DESELECT')
+        object.activate(mesh_object)
+        enterEditMode()
+        bpy.ops.mesh.normals_make_consistent()
+        enterObjectMode()
+
+    @staticmethod
+    def flipNormals(m):
+        m.flipNormals()
+
+    @staticmethod
+    def addMaterial(m, material):
+        m.materials.append(material)
+
+    @staticmethod
+    def getMaterial(m, index):
+        return m.materials[index]
+
+
+class vertex:
+    @staticmethod
+    def setNormal(v, normal):
+        v.normal=mathutils.Vector(normal)
+
+    @staticmethod
+    def getNormal(v):
+        return v.normal
+
+    @staticmethod
+    def setUv(v, uv):
+        # sticky ?
+        pass
+
+
+class face:
+    @staticmethod
+    def getVertexCount(face):
+        return len(face.vertices)
+
+    @staticmethod
+    def getVertices(face):
+        return face.vertices[:]
+
+    @staticmethod
+    def getIndices(face, count=3):
+        if count==3:
+            return [face.vertices[0], face.vertices[1], face.vertices[2]]
+        elif count==4:
+            return [face.vertices[0], face.vertices[1], face.vertices[2], face.vertices[3]]
+        else:
+            assert(False)
+
+    @staticmethod
+    def setMaterial(face, material_index):
+        face.material_index=material_index
+
+    @staticmethod
+    def getMaterialIndex(face):
+        return face.material_index
+
+    @staticmethod
+    def setNormal(face, normal):
+        face.normal=normal
+
+    @staticmethod
+    def getNormal(face):
+        return face.normal
+
+    @staticmethod
+    def setSmooth(face, isSmooth):
+        face.use_smooth=True if isSmooth else False
+
+
+class armature:
+    @staticmethod
+    def create():
+        global SCENE
+        armature = bpy.data.armatures.new('Armature')
+        armature_object=bpy.data.objects.new('Armature', armature)
+        SCENE.objects.link(armature_object)
+
+        armature_object.show_x_ray=True
+        armature.show_names=True
+        #armature.draw_type='OCTAHEDRAL'
+        armature.draw_type='STICK'
+        armature.use_deform_envelopes=False
+        armature.use_deform_vertex_groups=True
+        armature.use_mirror_x=True
+
+        return armature, armature_object
+
+    @staticmethod
+    def makeEditable(armature_object):
+        global SCENE
+        # 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)
+
+    @staticmethod
+    def createIkConstraint(armature_object, p_bone, effector_name, ik):
+        constraint = p_bone.constraints.new('IK')
+        constraint.chain_count=len(ik.children)
+        constraint.target=armature_object
+        constraint.subtarget=effector_name
+        constraint.use_tail=False
+        # not used. place folder when export.
+        constraint.weight=ik.weight
+        constraint.iterations=ik.iterations * 10
+        return constraint
+
+    @staticmethod
+    def createBone(armature, name):
+        return armature.edit_bones.new(name)
+
+    @staticmethod
+    def update(armature):
+        pass
+
+
+class bone:
+    @staticmethod
+    def setConnected(bone):
+        bone.use_connect=True
+
+    @staticmethod
+    def isConnected(b):
+        return b.connected
+
+    @staticmethod
+    def setLayerMask(bone, layers):
+        layer=[]
+        for i in range(32):
+            try:
+                layer.append(True if layers[i]!=0 else False)
+            except IndexError:
+                layer.append(False)
+        bone.layers=layer
+
+    @staticmethod
+    def getHeadLocal(b):
+        return b.head_local[0:3]
+
+    @staticmethod
+    def getTailLocal(b):
+        return b.tail_local[0:3]
+
+
+class constraint:
+    @staticmethod
+    def ikChainLen(c):
+        return c.chain_length
+
+    @staticmethod
+    def ikTarget(c):
+        return c.subtarget
+
+    @staticmethod
+    def ikItration(c):
+        return c.iterations
+
+    @staticmethod
+    def ikRotationWeight(c):
+        return c.weight
+
+    @staticmethod
+    def isIKSolver(c):
+        return c.type=='IK'
+
diff --git a/pymeshio/io_export_scene_mqo.py b/pymeshio/io_export_scene_mqo.py
new file mode 100755 (executable)
index 0000000..2ea8c64
--- /dev/null
@@ -0,0 +1,399 @@
+#!BPY
+# coding: utf-8
+
+"""
+Name: 'Metasequoia (.mqo)...'
+Blender: 245
+Group: 'Export'
+Tooltip: 'Save as Metasequoia MQO File'
+"""
+__author__= 'ousttrue'
+__url__ = ["http://gunload.web.fc2.com/blender/"]
+__version__= '2.2'
+__bpydoc__ = """\
+This script is an exporter to MQO file format.
+
+Usage:
+
+Run this script from "File->Export" menu.
+
+0.1 20080128:
+0.2 20100518: refactoring.
+0.3 20100606: integrate 2.4 and 2.5.
+0.4 20100626: refactoring.
+0.5 20100710: add [apply_modifier] option(2.5 only).
+0.6 20100714: remove shape_key when apply_modifier. fix material.
+2.0 20100724: update for Blender2.53.
+2.1 20101005: update for Blender2.54.
+2.2 20101228: update for Blender2.55.
+"""
+
+bl_addon_info = {
+        'category': 'Import/Export',
+        'name': 'Export: Metasequioa Model Format (.mqo)',
+        'author': 'ousttrue',
+        'version': (2, 1),
+        'blender': (2, 5, 3),
+        'location': 'File > Export',
+        'description': 'Export to the Metasequioa Model Format (.mqo)',
+        'warning': '', # used for warning icon and text in addons panel
+        'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
+        'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',
+        }
+
+import os
+import sys
+
+def isBlender24():
+    return sys.version_info[0]<3
+
+
+class MQOMaterial(object):
+    __slots__=[
+            'name', 'shader', 'r', 'g', 'b', 'a',
+            'dif', 'amb', 'emi',
+            ]
+    def __init__(self, name, shader=3):
+        self.name=name
+        self.shader=shader
+        self.r=0.5
+        self.g=0.5
+        self.b=0.5
+        self.a=1
+        self.dif=1
+        self.amb=0
+        self.emi=0
+
+    def __str__(self):
+        return "\"%s\" shader(%d) col(%f %f %f %f) dif(%f) amb(%f) emi(%f)" % (
+                self.name, self.shader, self.r, self.g, self.b, self.a,
+                self.dif, self.amb, self.emi
+                )
+
+
+if isBlender24():
+    # for 2.4
+    import Blender
+    from Blender import Mathutils
+    import bpy
+
+    # wrapper
+    import bl24 as bl
+
+    def materialToMqo(m):
+        material=MQOMaterial(m.name, 3)
+        material.r=m.rgbCol[0]
+        material.g=m.rgbCol[1]
+        material.b=m.rgbCol[2]
+        material.a=m.alpha
+        return material
+
+else:
+    # for 2.5
+    import bpy
+
+    # wrapper
+    import bl25 as bl
+
+    def materialToMqo(m):
+        material=MQOMaterial(m.name, 3)
+        material.r=m.diffuse_color[0]
+        material.g=m.diffuse_color[1]
+        material.b=m.diffuse_color[2]
+        material.a=m.alpha
+        material.amb=m.ambient
+        material.emi=m.emit
+        return material
+
+def apply_transform(vec, matrix):
+    x, y, z = vec
+    xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
+    return    x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\
+            x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\
+            x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
+
+def convert_to_mqo(vec):
+    return vec.x, vec.z, -vec.y
+
+
+class OutlineNode(object):
+    __slots__=['o', 'children']
+    def __init__(self, o):
+        self.o=o
+        self.children=[]
+
+    def __str__(self):
+        return "<Node %s>" % self.o
+
+
+class ObjectInfo(object):
+    __slots__=['object', 'depth', 'material_map']
+    def __init__(self, o, depth):
+        self.object=o
+        self.depth=depth
+        self.material_map={}
+
+    def __str__(self):
+        return "<ObjectInfo %d %s>" % (self.depth, self.object)
+
+
+class MqoExporter(object):
+    __slots__=["materials", "objects", 'scale', 'apply_modifier',]
+    def __init__(self, scale, apply_modifier):
+        self.objects=[]
+        self.materials=[]
+        self.scale=scale
+        self.apply_modifier=apply_modifier
+
+    def setup(self, scene):
+        # 木構造を構築する
+        object_node_map={}
+        for o in scene.objects:
+            object_node_map[o]=OutlineNode(o)
+        for node in object_node_map.values():
+            if node.o.parent:
+                object_node_map[node.o.parent].children.append(node)
+
+        # ルートを得る
+        root=object_node_map[scene.objects.active]
+
+        # 情報を集める
+        if root.o.type.upper()=='EMPTY':
+            # depth調整 
+            for node in root.children:
+                self.__setup(node)
+        else:
+            self.__setup(root)
+
+    def __setup(self, node, depth=0):
+        info=ObjectInfo(node.o, depth)
+        self.objects.append(info)
+        if node.o.type.upper()=='MESH':
+            # set material index
+            for i, m in enumerate(node.o.data.materials):
+                info.material_map[i]=self.__getOrAddMaterial(m)
+        # recursive
+        for child in node.children:
+            self.__setup(child, depth+1)
+            
+    def __getOrAddMaterial(self, material):
+        for i, m in enumerate(self.materials):
+            if m==material:
+                return i
+        index=len(self.materials)
+        self.materials.append(material)
+        return index
+
+    def write(self, path):
+        bl.message("open: "+path)
+        io=bl.Writer(path, 'cp932')
+        self.__write_header(io)
+        self.__write_scene(io)
+        print("Writing MaterialChunk")
+        self.__write_materials(io, os.path.dirname(path))
+        print("Writing ObjectChunk")
+        for info in self.objects:
+            self.__write_object(io, info)
+        io.write("Eof\r\n")
+        io.flush()
+        io.close()
+
+    def __write_header(self, io):
+        io.write("Metasequoia Document\r\n")
+        io.write("Format Text Ver 1.0\r\n")
+        io.write("\r\n")
+
+    def __write_scene(self, io):
+        print("Writing SceneChunk")
+        io.write("Scene {\r\n")
+        io.write("}\r\n")
+
+    def __write_materials(self, io, dirname):
+        # each material    
+        io.write("Material %d {\r\n" % (len(self.materials)))
+        for m in self.materials:
+            io.write(str(materialToMqo(m)))
+            # ToDo separated alpha texture
+            for filename in bl.material.eachTexturePath(m):
+                if len(dirname)>0 and filename.startswith(dirname):
+                    # 相対パスに変換する
+                    filename=filename[len(dirname)+1:]
+                io.write(" tex(\"%s\")" % filename)
+                break
+            io.write("\r\n") 
+        # end of chunk
+        io.write("}\r\n") 
+
+    def __write_object(self, io, info):
+        print(info)
+
+        obj=info.object
+        if obj.type.upper()=='MESH' or obj.type.upper()=='EMPTY':
+            pass
+        else:
+            print(obj.type)
+            return
+
+        io.write("Object \""+obj.name+"\" {\r\n")
+
+        # depth
+        io.write("\tdepth %d\r\n" % info.depth)
+
+        # mirror
+        if not self.apply_modifier:
+            if bl.modifier.hasType(obj, 'MIRROR'):
+                    io.write("\tmirror 1\r\n")
+                    io.write("\tmirror_axis 1\r\n")
+
+        if obj.type.upper()=='MESH':
+            # duplicate and applyMatrix
+            copyMesh, copyObj=bl.object.duplicate(obj)
+            # apply transform
+            copyObj.scale=obj.scale
+            bpy.ops.object.scale_apply()
+            copyObj.rotation_euler=obj.rotation_euler
+            bpy.ops.object.rotation_apply()
+            copyObj.location=obj.location
+            bpy.ops.object.location_apply()
+            # apply modifier
+            if self.apply_modifier:
+                # remove shape key
+                while bl.object.hasShapeKey(copyObj):
+                    bpy.ops.object.shape_key_remove()
+                for m in [m for m in copyObj.modifiers]:
+                    if m.type=='SOLIDFY':
+                        continue
+                    elif m.type=='ARMATURE':
+                        bpy.ops.object.modifier_apply(modifier=m.name)
+                    elif m.type=='MIRROR':
+                        bpy.ops.object.modifier_apply(modifier=m.name)
+                    else:
+                        print(m.type)
+            # write mesh
+            self.__write_mesh(io, copyMesh, info.material_map)
+            bl.object.delete(copyObj)
+
+        io.write("}\r\n") # end of object
+
+    def __write_mesh(self, io, mesh, material_map):
+        # vertices
+        io.write("\tvertex %d {\r\n" % len(mesh.verts))
+        for vert in mesh.verts:
+            x, y, z = convert_to_mqo(vert.co)
+            io.write("\t\t%f %f %f\r\n" % 
+                    (x*self.scale, y*self.scale, z*self.scale)) # rotate to y-up
+        io.write("\t}\r\n")
+
+        # faces
+        io.write("\tface %d {\r\n" % len(mesh.faces))
+        for i, face in enumerate(mesh.faces):
+            count=bl.face.getVertexCount(face)
+            # V
+            io.write("\t\t%d V(" % count)
+            for j in reversed(bl.face.getVertices(face)):
+                io.write("%d " % j)
+            io.write(")")
+            # mat
+            if len(mesh.materials):
+                io.write(" M(%d)" % 
+                        material_map[bl.face.getMaterialIndex(face)])
+            # UV
+            if bl.mesh.hasUV(mesh) and bl.mesh.hasFaceUV(mesh, i, face):
+                io.write(" UV(")
+                for uv in reversed(bl.mesh.getFaceUV(mesh, i, face, count)):
+                    # reverse vertical value
+                    io.write("%f %f " % (uv[0], 1.0-uv[1])) 
+                io.write(")")
+            io.write("\r\n")
+        io.write("\t}\r\n") # end of faces
+
+
+def __execute(filename, scene, scale=10, apply_modifier=False):
+    if scene.objects.active:
+        exporter=MqoExporter(scale, apply_modifier)
+        exporter.setup(scene)
+        exporter.write(filename)
+    else:
+        bl.message('no active object !')
+
+
+if isBlender24():
+    # for 2.4
+    def execute_24(filename):
+        scene=Blender.Scene.GetCurrent()
+        bl.initialize('mqo_export', scene)
+        __execute(
+                filename.decode(bl.INTERNAL_ENCODING), 
+                scene, False)
+        bl.finalize()
+
+    # execute
+    Blender.Window.FileSelector(
+            execute_24, 
+            'Export Metasequoia MQO', 
+            Blender.sys.makename(ext='.mqo'))
+
+else:
+    # for 2.5
+    def execute_25(path, scene, scale, apply_modifier):
+        bl.initialize('mqo_export', scene)
+        __execute(path, scene, scale, apply_modifier)
+        bl.finalize()
+
+    # operator
+    class EXPORT_OT_mqo(bpy.types.Operator):
+        '''Save a Metasequoia MQO file.'''
+        bl_idname = "export_scene.mqo"
+        bl_label = 'Export MQO'
+
+        # List of operator properties, the attributes will be assigned
+        # to the class instance from the operator settings before calling.
+        filepath = bpy.props.StringProperty()
+        filename = bpy.props.StringProperty()
+        directory = bpy.props.StringProperty()
+
+        scale = bpy.props.FloatProperty(
+                name="Scale", 
+                description="Scale the MQO by this value", 
+                min=0.0001, max=1000000.0, 
+                soft_min=0.001, soft_max=100.0, default=10.0)
+
+        apply_modifier = bpy.props.BoolProperty(
+                name="ApplyModifier", 
+                description="Would apply modifiers", 
+                default=False)
+
+        def execute(self, context):
+            execute_25(
+                    self.properties.filepath, 
+                    context.scene, 
+                    self.properties.scale,
+                    self.properties.apply_modifier)
+            return 'FINISHED'
+
+        def invoke(self, context, event):
+            wm=context.window_manager
+            try:
+                wm.fileselect_add(self)
+            except:
+                wm.add_fileselect(self)
+            return 'RUNNING_MODAL'
+
+    # register menu
+    def menu_func(self, context): 
+        default_path=bpy.data.filepath.replace(".blend", ".mqo")
+        self.layout.operator(
+                EXPORT_OT_mqo.bl_idname, 
+                text="Metasequoia (.mqo)",
+                icon='PLUGIN'
+                ).filepath=default_path
+
+    def register():
+        bpy.types.INFO_MT_file_export.append(menu_func)
+
+    def unregister():
+        bpy.types.INFO_MT_file_export.remove(menu_func)
+
+    if __name__ == "__main__":
+        register()
+
diff --git a/pymeshio/io_export_scene_pmd.py b/pymeshio/io_export_scene_pmd.py
new file mode 100755 (executable)
index 0000000..8666bd6
--- /dev/null
@@ -0,0 +1,1274 @@
+#!BPY
+# coding: utf-8
+"""
+ Name: 'MikuMikuDance model (.pmd)...'
+ Blender: 248
+ Group: 'Export'
+ Tooltip: 'Export PMD file for MikuMikuDance.'
+"""
+__author__= ["ousttrue"]
+__version__= "2.2"
+__url__=()
+__bpydoc__="""
+pmd Importer
+
+This script exports a pmd model.
+
+0.1 20100318: first implementation.
+0.2 20100519: refactoring. use C extension.
+1.0 20100530: implement basic features.
+1.1 20100612: integrate 2.4 and 2.5.
+1.2 20100616: implement rigid body.
+1.3 20100619: fix rigid body, bone weight.
+1.4 20100626: refactoring.
+1.5 20100629: sphere map.
+1.6 20100710: toon texture & bone group.
+1.7 20100711: separate vertex with normal or uv.
+2.0 20100724: update for Blender2.53.
+2.1 20100731: add full python module.
+2.2 20101005: update for Blender2.54.
+2.3 20101228: update for Blender2.55.
+"""
+
+bl_addon_info = {
+        'category': 'Import/Export',
+        'name': 'Export: MikuMikuDance Model Format (.pmd)',
+        'author': 'ousttrue',
+        'version': (2, 2),
+        'blender': (2, 5, 3),
+        'location': 'File > Export',
+        'description': 'Export to the MikuMikuDance Model Format (.pmd)',
+        'warning': '', # used for warning icon and text in addons panel
+        'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
+        'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',
+        }
+
+MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
+MMD_MB_NAME='mb_name'
+MMD_MB_COMMENT='mb_comment'
+MMD_COMMENT='comment'
+BASE_SHAPE_NAME='Basis'
+RIGID_NAME='rigid_name'
+RIGID_SHAPE_TYPE='rigid_shape_type'
+RIGID_PROCESS_TYPE='rigid_process_type'
+RIGID_BONE_NAME='rigid_bone_name'
+#RIGID_LOCATION='rigid_loation'
+RIGID_GROUP='ribid_group'
+RIGID_INTERSECTION_GROUP='rigid_intersection_group'
+RIGID_WEIGHT='rigid_weight'
+RIGID_LINEAR_DAMPING='rigid_linear_damping'
+RIGID_ANGULAR_DAMPING='rigid_angular_damping'
+RIGID_RESTITUTION='rigid_restitution'
+RIGID_FRICTION='rigid_friction'
+CONSTRAINT_NAME='constraint_name'
+CONSTRAINT_A='const_a'
+CONSTRAINT_B='const_b'
+CONSTRAINT_POS_MIN='const_pos_min'
+CONSTRAINT_POS_MAX='const_pos_max'
+CONSTRAINT_ROT_MIN='const_rot_min'
+CONSTRAINT_ROT_MAX='const_rot_max'
+CONSTRAINT_SPRING_POS='const_spring_pos'
+CONSTRAINT_SPRING_ROT='const_spring_rot'
+TOON_TEXTURE_OBJECT='ToonTextures'
+
+
+###############################################################################
+# import
+###############################################################################
+import os
+import sys
+
+try:
+    # C extension
+    from meshio import pmd, englishmap
+    print('use meshio C module')
+except ImportError:
+    # full python
+    from pymeshio import englishmap
+    from pymeshio import mmd as pmd
+    pmd.IO=pmd.PMDLoader
+
+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
+
+    def setMaterialParams(material, m):
+        # diffuse
+        material.diffuse.r=m.R
+        material.diffuse.g=m.G
+        material.diffuse.b=m.B
+        material.diffuse.a=m.alpha
+        # specular
+        material.shinness=0 if m.spec<1e-5 else m.spec*10
+        material.specular.r=m.specR
+        material.specular.g=m.specG
+        material.specular.b=m.specB
+        # ambient
+        material.ambient.r=m.mirR
+        material.ambient.g=m.mirG
+        material.ambient.b=m.mirB
+        # flag
+        material.flag=1 if m.enableSSS else 0
+
+    def toCP932(s):
+        return s
+
+
+else:
+    # for 2.5
+    import bpy
+    import mathutils
+
+    # wrapper
+    import bl25 as bl
+
+    xrange=range
+
+    def setMaterialParams(material, m):
+        # diffuse
+        material.diffuse.r=m.diffuse_color[0]
+        material.diffuse.g=m.diffuse_color[1]
+        material.diffuse.b=m.diffuse_color[2]
+        material.diffuse.a=m.alpha
+        # specular
+        material.shinness=0 if m.specular_toon_size<1e-5 else m.specular_hardness*10
+        material.specular.r=m.specular_color[0]
+        material.specular.g=m.specular_color[1]
+        material.specular.b=m.specular_color[2]
+        # ambient
+        material.ambient.r=m.mirror_color[0]
+        material.ambient.g=m.mirror_color[1]
+        material.ambient.b=m.mirror_color[2]
+        # flag
+        material.flag=1 if m.subsurface_scattering.enabled else 0
+        # toon
+        material.toon_index=7
+
+    def toCP932(s):
+        return s.encode('cp932')
+
+
+class Node(object):
+    __slots__=['o', 'children']
+    def __init__(self, o):
+        self.o=o
+        self.children=[]
+
+
+###############################################################################
+# Blenderのメッシュをワンスキンメッシュ化する
+###############################################################################
+def near(x, y, EPSILON=1e-5):
+    d=x-y
+    return d>=-EPSILON and d<=EPSILON
+
+
+class VertexAttribute(object):
+    __slots__=[
+            'nx', 'ny', 'nz', # normal
+            'u', 'v', # uv
+            ]
+    def __init__(self, nx, ny, nz, u, v):
+        self.nx=nx
+        self.ny=ny
+        self.nz=nz
+        self.u=u
+        self.v=v
+
+    def __str__(self):
+        return "<vkey: %f, %f, %f, %f, %f>" % (
+                self.nx, self.ny, self.nz, self.u, self.v)
+
+    def __hash__(self):
+        return self.nx + self.ny + self.nz + self.u + self.v
+
+    def __eq__(self, rhs):
+        return self.nx==rhs.nx and self.ny==rhs.ny and self.nz==rhs.nz and self.u==rhs.u and self.v==rhs.v
+
+
+class VertexKey(object):
+    __slots__=[
+            'obj_index', 'index',
+            ]
+
+    def __init__(self, obj_index, index):
+        self.obj_index=obj_index
+        self.index=index
+
+    def __str__(self):
+        return "<vkey: %d, %d>" % (self.obj_index, self.index)
+
+    def __hash__(self):
+        return self.index*100+self.obj_index
+
+    def __eq__(self, rhs):
+        return self.obj_index==rhs.obj_index and self.index==rhs.index
+
+
+class VertexArray(object):
+    """
+    頂点配列
+    """
+    __slots__=[
+            'indexArrays',
+            'positions',
+            'attributes', # normal and uv
+            'b0', 'b1', 'weight',
+            'vertexMap',
+            'objectMap',
+            ]
+    def __init__(self):
+        # indexArrays split with each material
+        self.indexArrays={}
+
+        self.positions=[]
+        self.attributes=[]
+        self.b0=[]
+        self.b1=[]
+        self.weight=[]
+
+        self.vertexMap={}
+        self.objectMap={}
+
+    def __str__(self):
+        return "<VertexArray %d positions, %d indexArrays>" % (
+                len(self.positions), len(self.indexArrays))
+
+    def zip(self):
+        return zip(
+                self.positions, self.attributes,
+                self.b0, self.b1, self.weight)
+
+    def each(self):
+        keys=[key for key in self.indexArrays.keys()]
+        keys.sort()
+        for key in keys:
+            yield(key, self.indexArrays[key])
+
+    def __addOrGetIndex(self, obj_index, base_index, pos, normal, uv, b0, b1, weight0):
+        key=VertexKey(obj_index, base_index)
+        attribute=VertexAttribute( 
+                normal[0], normal[1], normal[2],
+                uv[0], uv[1])
+        if key in self.vertexMap:
+            if attribute in self.vertexMap[key]:
+                return self.vertexMap[key][attribute]
+            else:
+                return self.__addVertex(self.vertexMap[key],
+                        pos, attribute, b0, b1, weight0)
+        else:
+            vertexMapKey={}
+            self.vertexMap[key]=vertexMapKey
+            return self.__addVertex(vertexMapKey,
+                    pos, attribute, b0, b1, weight0)
+
+    def __addVertex(self, vertexMapKey, pos, attribute, b0, b1, weight0):
+        index=len(self.positions)
+        vertexMapKey[attribute]=index
+        # position
+        self.positions.append((pos.x, pos.y, pos.z))
+        # unique attribute
+        self.attributes.append(attribute)
+        # shared attribute
+        self.b0.append(b0)
+        self.b1.append(b1)
+        self.weight.append(weight0)
+        assert(index<=65535)
+        return index
+            
+    def getMappedIndex(self, obj_name, base_index):
+        return self.vertexMap[VertexKey(self.objectMap[obj_name], base_index)]
+
+    def addTriangle(self,
+            object_name, material,
+            base_index0, base_index1, base_index2,
+            pos0, pos1, pos2,
+            n0, n1, n2,
+            uv0, uv1, uv2,
+            b0_0, b0_1, b0_2,
+            b1_0, b1_1, b1_2,
+            weight0, weight1, weight2
+            ):
+        if object_name in self.objectMap:
+            obj_index=self.objectMap[object_name]
+        else:
+            obj_index=len(self.objectMap)
+            self.objectMap[object_name]=obj_index
+        index0=self.__addOrGetIndex(obj_index, base_index0, pos0, n0, uv0, b0_0, b1_0, weight0)
+        index1=self.__addOrGetIndex(obj_index, base_index1, pos1, n1, uv1, b0_1, b1_1, weight1)
+        index2=self.__addOrGetIndex(obj_index, base_index2, pos2, n2, uv2, b0_2, b1_2, weight2)
+
+        if not material in self.indexArrays:
+            self.indexArrays[material]=[]
+        self.indexArrays[material]+=[index0, index1, index2]
+
+
+class Morph(object):
+    __slots__=['name', 'type', 'offsets']
+    def __init__(self, name, type):
+        self.name=name
+        self.type=type
+        self.offsets=[]
+
+    def add(self, index, offset):
+        self.offsets.append((index, offset))
+
+    def sort(self):
+        if isBlender24():
+            self.offsets.sort(lambda l, r: l[0]-r[0])
+        else:
+            self.offsets.sort(key=lambda e: e[0])
+
+    def __str__(self):
+        return "<Morph %s>" % self.name
+
+class IKSolver(object):
+    __slots__=['target', 'effector', 'length', 'iterations', 'weight']
+    def __init__(self, target, effector, length, iterations, weight):
+        self.target=target
+        self.effector=effector
+        self.length=length
+        self.iterations=iterations
+        self.weight=weight
+
+
+class OneSkinMesh(object):
+    __slots__=['vertexArray', 'morphList', 'rigidbodies', 'constraints', ]
+    def __init__(self):
+        self.vertexArray=VertexArray()
+        self.morphList=[]
+        self.rigidbodies=[]
+        self.constraints=[]
+
+    def __str__(self):
+        return "<OneSkinMesh %s, morph:%d>" % (
+                self.vertexArray,
+                len(self.morphList))
+
+    def addMesh(self, obj):
+        if not bl.object.isVisible(obj):
+            return
+        self.__mesh(obj)
+        self.__skin(obj)
+        self.__rigidbody(obj)
+        self.__constraint(obj)
+
+    def __getWeightMap(self, obj, mesh):
+        # bone weight
+        weightMap={}
+        secondWeightMap={}
+        def setWeight(i, name, w):
+            if w>0:
+                if i in weightMap:
+                    if i in secondWeightMap:
+                        # 上位2つのweightを採用する
+                        if w<secondWeightMap[i][1]:
+                            pass
+                        elif w<weightMap[i][1]:
+                            # 2つ目を入れ替え
+                            secondWeightMap[i]=(name, w)
+                        else:
+                            # 1つ目を入れ替え
+                            weightMap[i]=(name, w)
+                    else:
+                        if w>weightMap[i][1]:
+                            # 多い方をweightMapに
+                            secondWeightMap[i]=weightMap[i]
+                            weightMap[i]=(name, w)
+                        else:
+                            secondWeightMap[i]=(name, w)
+                else:
+                    weightMap[i]=(name, w)
+
+        # ToDo bone weightと関係ないvertex groupを除外する
+        if isBlender24():
+            for name in bl.object.getVertexGroupNames(obj):
+                for i, w in mesh.getVertsFromGroup(name, 1):
+                    setWeight(i, name, w)
+        else:
+            for i, v in enumerate(mesh.verts):
+                if len(v.groups)>0:
+                    for g in v.groups:
+                        setWeight(i, obj.vertex_groups[g.group].name, g.weight)
+                else:
+                    setWeight(i, obj.vertex_groups[0].name, 1)
+
+        # 合計値が1になるようにする
+        for i in xrange(len(mesh.verts)):
+            if i in secondWeightMap:
+                secondWeightMap[i]=(secondWeightMap[i][0], 1.0-weightMap[i][1])
+            elif i in weightMap:
+                weightMap[i]=(weightMap[i][0], 1.0)
+                secondWeightMap[i]=("", 0)
+            else:
+                print("no weight vertex")
+                weightMap[i]=("", 0)
+                secondWeightMap[i]=("", 0)
+
+        return weightMap, secondWeightMap
+
+    def __processFaces(self, obj_name, mesh, weightMap, secondWeightMap):
+        # 各面の処理
+        for i, face in enumerate(mesh.faces):
+            faceVertexCount=bl.face.getVertexCount(face)
+            material=mesh.materials[bl.face.getMaterialIndex(face)]
+            v=[mesh.verts[index] for index in bl.face.getVertices(face)]
+            uv=bl.mesh.getFaceUV(
+                    mesh, i, face, bl.face.getVertexCount(face))
+            # flip triangle
+            if faceVertexCount==3:
+                # triangle
+                self.vertexArray.addTriangle(
+                        obj_name, material.name,
+                        v[2].index, 
+                        v[1].index, 
+                        v[0].index,
+                        v[2].co, 
+                        v[1].co, 
+                        v[0].co,
+                        bl.vertex.getNormal(v[2]), 
+                        bl.vertex.getNormal(v[1]), 
+                        bl.vertex.getNormal(v[0]),
+                        uv[2], 
+                        uv[1], 
+                        uv[0],
+                        weightMap[v[2].index][0],
+                        weightMap[v[1].index][0],
+                        weightMap[v[0].index][0],
+                        secondWeightMap[v[2].index][0],
+                        secondWeightMap[v[1].index][0],
+                        secondWeightMap[v[0].index][0],
+                        weightMap[v[2].index][1],
+                        weightMap[v[1].index][1],
+                        weightMap[v[0].index][1]
+                        )
+            elif faceVertexCount==4:
+                # quadrangle
+                self.vertexArray.addTriangle(
+                        obj_name, material.name,
+                        v[2].index, 
+                        v[1].index, 
+                        v[0].index,
+                        v[2].co, 
+                        v[1].co, 
+                        v[0].co,
+                        bl.vertex.getNormal(v[2]), 
+                        bl.vertex.getNormal(v[1]), 
+                        bl.vertex.getNormal(v[0]), 
+                        uv[2], 
+                        uv[1], 
+                        uv[0],
+                        weightMap[v[2].index][0],
+                        weightMap[v[1].index][0],
+                        weightMap[v[0].index][0],
+                        secondWeightMap[v[2].index][0],
+                        secondWeightMap[v[1].index][0],
+                        secondWeightMap[v[0].index][0],
+                        weightMap[v[2].index][1],
+                        weightMap[v[1].index][1],
+                        weightMap[v[0].index][1]
+                        )
+                self.vertexArray.addTriangle(
+                        obj_name, material.name,
+                        v[0].index, 
+                        v[3].index, 
+                        v[2].index,
+                        v[0].co, 
+                        v[3].co, 
+                        v[2].co,
+                        bl.vertex.getNormal(v[0]), 
+                        bl.vertex.getNormal(v[3]), 
+                        bl.vertex.getNormal(v[2]), 
+                        uv[0], 
+                        uv[3], 
+                        uv[2],
+                        weightMap[v[0].index][0],
+                        weightMap[v[3].index][0],
+                        weightMap[v[2].index][0],
+                        secondWeightMap[v[0].index][0],
+                        secondWeightMap[v[3].index][0],
+                        secondWeightMap[v[2].index][0],
+                        weightMap[v[0].index][1],
+                        weightMap[v[3].index][1],
+                        weightMap[v[2].index][1]
+                        )
+
+    def __mesh(self, obj):
+        if isBlender24():
+            pass
+        else:
+            if RIGID_SHAPE_TYPE in obj:
+                return
+            if CONSTRAINT_A in obj:
+                return
+
+        #if not bl.modifier.hasType(obj, 'ARMATURE'):
+        #    return
+
+        bl.message("export: %s" % obj.name)
+
+        # メッシュのコピーを生成してオブジェクトの行列を適用する
+        copyMesh, copyObj=bl.object.duplicate(obj)
+        if len(copyMesh.verts)>0:
+            # apply transform
+            copyObj.scale=obj.scale
+            bpy.ops.object.scale_apply()
+            copyObj.rotation_euler=obj.rotation_euler
+            bpy.ops.object.rotation_apply()
+            copyObj.location=obj.location
+            bpy.ops.object.location_apply()
+            # apply modifier
+            for m in [m for m in copyObj.modifiers]:
+                if m.type=='SOLIDFY':
+                    continue
+                elif m.type=='ARMATURE':
+                    continue
+                elif m.type=='MIRROR':
+                    bpy.ops.object.modifier_apply(modifier=m.name)
+                else:
+                    print(m.type)
+
+            weightMap, secondWeightMap=self.__getWeightMap(copyObj, copyMesh)
+            self.__processFaces(obj.name, copyMesh, weightMap, secondWeightMap)
+        bl.object.delete(copyObj)
+
+    def createEmptyBasicSkin(self):
+        self.__getOrCreateMorph('base', 0)
+
+    def __skin(self, obj):
+        if not bl.object.hasShapeKey(obj):
+            return
+
+        indexRelativeMap={}
+        blenderMesh=bl.object.getData(obj)
+        baseMorph=None
+
+        # shape keys
+        vg=bl.object.getVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
+
+        # base
+        used=set()
+        for b in bl.object.getShapeKeys(obj):
+            if b.name==BASE_SHAPE_NAME:
+                baseMorph=self.__getOrCreateMorph('base', 0)
+                basis=b
+
+                relativeIndex=0
+                for index in vg:
+                    v=bl.shapekey.getByIndex(b, index)
+                    pos=[v[0], v[1], v[2]]
+
+                    indices=self.vertexArray.getMappedIndex(obj.name, index)
+                    for attribute, i in indices.items():
+                        if i in used:
+                            continue
+                        used.add(i)
+
+                        baseMorph.add(i, pos)
+                        indexRelativeMap[i]=relativeIndex
+                        relativeIndex+=1
+
+                break
+        assert(basis)
+        print(basis.name, len(baseMorph.offsets))
+
+        if len(baseMorph.offsets)==0:
+            return
+
+        # shape keys
+        for b in bl.object.getShapeKeys(obj):
+            if b.name==BASE_SHAPE_NAME:
+                continue
+
+            print(b.name)
+            morph=self.__getOrCreateMorph(b.name, 4)
+            used=set()
+            for index, src, dst in zip(
+                    xrange(len(blenderMesh.verts)),
+                    bl.shapekey.get(basis),
+                    bl.shapekey.get(b)):
+                offset=[dst[0]-src[0], dst[1]-src[1], dst[2]-src[2]]
+                if offset[0]==0 and offset[1]==0 and offset[2]==0:
+                    continue
+                if index in vg:
+                    indices=self.vertexArray.getMappedIndex(obj.name, index)
+                    for attribute, i in indices.items():
+                        if i in used:
+                            continue
+                        used.add(i) 
+                        morph.add(indexRelativeMap[i], offset)
+            assert(len(morph.offsets)<len(baseMorph.offsets))
+
+        # sort skinmap
+        original=self.morphList[:]
+        def getIndex(morph):
+            for i, v in enumerate(englishmap.skinMap):
+                if v[0]==morph.name:
+                    return i
+            print(morph)
+            return len(englishmap.skinMap)
+        if isBlender24():
+            self.morphList.sort(lambda l, r: getIndex(l)-getIndex(r))
+        else:
+            self.morphList.sort(key=getIndex)
+
+    def __rigidbody(self, obj):
+        if isBlender24():
+            return
+        if not RIGID_SHAPE_TYPE in obj:
+            return
+        self.rigidbodies.append(obj)
+
+    def __constraint(self, obj):
+        if isBlender24():
+            return
+        if not CONSTRAINT_A in obj:
+            return
+        self.constraints.append(obj)
+
+    def __getOrCreateMorph(self, name, type):
+        for m in self.morphList:
+            if m.name==name:
+                return m
+        m=Morph(name, type)
+        self.morphList.append(m)
+        return m
+
+    def getVertexCount(self):
+        return len(self.vertexArray.positions)
+
+
+class Bone(object):
+    __slots__=['index', 'name', 'ik_index',
+            'pos', 'tail', 'parent_index', 'tail_index', 'type', 'isConnect']
+    def __init__(self, name, pos, tail, isConnect):
+        self.index=-1
+        self.name=name
+        self.pos=pos
+        self.tail=tail
+        self.parent_index=None
+        self.tail_index=None
+        self.type=0
+        self.isConnect=isConnect
+        self.ik_index=0
+
+    def __eq__(self, rhs):
+        return self.index==rhs.index
+
+    def __str__(self):
+        return "<Bone %s %d>" % (self.name, self.type)
+
+class BoneBuilder(object):
+    __slots__=['bones', 'boneMap', 'ik_list', 'bone_groups',]
+    def __init__(self):
+        self.bones=[]
+        self.boneMap={}
+        self.ik_list=[]
+        self.bone_groups=[]
+
+    def getBoneGroup(self, bone):
+        for i, g in enumerate(self.bone_groups):
+            for b in g[1]:
+                if b==bone.name:
+                    return i+1
+        print('no gorup', bone)
+        return 0
+
+    def build(self, armatureObj):
+        if not armatureObj:
+            return
+
+        bl.message("build skeleton")
+        armature=bl.object.getData(armatureObj)
+
+        ####################
+        # bone group
+        ####################
+        for g in bl.object.boneGroups(armatureObj):
+            self.bone_groups.append((g.name, []))
+
+        ####################
+        # get bones
+        ####################
+        for b in armature.bones.values():
+            if not b.parent:
+                # root bone
+                bone=Bone(b.name, 
+                        bl.bone.getHeadLocal(b),
+                        bl.bone.getTailLocal(b),
+                        False)
+                self.__addBone(bone)
+                self.__getBone(bone, b)
+
+        for b in armature.bones.values():
+            if not b.parent:
+                self.__checkConnection(b, None)
+
+        ####################
+        # get IK
+        ####################
+        pose = bl.object.getPose(armatureObj)
+        for b in pose.bones.values():
+            ####################
+            # assing bone group
+            ####################
+            self.__assignBoneGroup(b, b.bone_group)
+            for c in b.constraints:
+                if bl.constraint.isIKSolver(c):
+                    ####################
+                    # IK target
+                    ####################
+                    target=self.__boneByName(bl.constraint.ikTarget(c))
+                    target.type=2
+
+                    ####################
+                    # IK effector
+                    ####################
+                    # IK 接続先
+                    link=self.__boneByName(b.name)
+                    link.type=6
+
+                    # IK chain
+                    e=b.parent
+                    chainLength=bl.constraint.ikChainLen(c)
+                    for i in range(chainLength):
+                        # IK影響下
+                        chainBone=self.__boneByName(e.name)
+                        chainBone.type=4
+                        chainBone.ik_index=target.index
+                        e=e.parent
+                    self.ik_list.append(
+                            IKSolver(target, link, chainLength, 
+                                int(bl.constraint.ikItration(c) * 0.1), 
+                                bl.constraint.ikRotationWeight(c)
+                                ))
+
+        ####################
+
+        # boneのsort
+        self._sortBy()
+        self._fix()
+        # IKのsort
+        def getIndex(ik):
+            for i, v in enumerate(englishmap.boneMap):
+                if v[0]==ik.target.name:
+                    return i
+            return len(englishmap.boneMap)
+        if isBlender24():
+            self.ik_list.sort(lambda l, r: getIndex(l)-getIndex(r))
+        else:
+            self.ik_list.sort(key=getIndex)
+
+    def __assignBoneGroup(self, poseBone, boneGroup):
+        if boneGroup:
+            for g in self.bone_groups:
+                if g[0]==boneGroup.name:
+                    g[1].append(poseBone.name)
+
+    def __checkConnection(self, b, p):
+        if bl.bone.isConnected(b):
+            parent=self.__boneByName(p.name)
+            parent.isConnect=True
+
+        for c in b.children:
+            self.__checkConnection(c, b)
+
+    def _sortBy(self):
+        """
+        boneMap順に並べ替える
+        """
+        boneMap=englishmap.boneMap
+        original=self.bones[:]
+        def getIndex(bone):
+            for i, k_v in enumerate(boneMap):
+                if k_v[0]==bone.name:
+                    return i
+            print(bone)
+            return len(boneMap)
+
+        if isBlender24():
+            self.bones.sort(lambda l, r: getIndex(l)-getIndex(r))
+        else:
+            self.bones.sort(key=getIndex)
+
+        sortMap={}
+        for i, b in enumerate(self.bones):
+            src=original.index(b)
+            sortMap[src]=i
+        for b in self.bones:
+            b.index=sortMap[b.index]
+            if b.parent_index:
+                b.parent_index=sortMap[b.parent_index]
+            if b.tail_index:
+                b.tail_index=sortMap[b.tail_index]
+            if b.ik_index>0:
+                b.ik_index=sortMap[b.ik_index]
+
+    def _fix(self):
+        """
+        調整
+        """
+        for b in self.bones:
+            # parent index
+            if b.parent_index==None:
+                b.parent_index=0xFFFF
+            else:
+                if b.type==6 or b.type==7:
+                    # fix tail bone
+                    parent=self.bones[b.parent_index]
+                    #print('parnet', parent.name)
+                    parent.tail_index=b.index
+
+        for b in self.bones:
+            if b.tail_index==None:
+                b.tail_index=0
+            elif b.type==9:
+                b.tail_index==0
+
+    def getIndex(self, bone):
+        for i, b in enumerate(self.bones):
+            if b==bone:
+                return i
+        assert(false)
+
+    def indexByName(self, name):
+        if name=='':
+            return 0
+        else:
+            return self.getIndex(self.__boneByName(name))
+
+    def __boneByName(self, name):
+        return self.boneMap[name]
+                    
+    def __getBone(self, parent, b):
+        if len(b.children)==0:
+            parent.type=7
+            return
+
+        for i, c in enumerate(b.children):
+            bone=Bone(c.name, 
+                    bl.bone.getHeadLocal(c),
+                    bl.bone.getTailLocal(c),
+                    bl.bone.isConnected(c))
+            self.__addBone(bone)
+            if parent:
+                bone.parent_index=parent.index
+                #if i==0:
+                if bone.isConnect or (not parent.tail_index and parent.tail==bone.pos):
+                    parent.tail_index=bone.index
+            self.__getBone(bone, c)
+
+    def __addBone(self, bone):
+        bone.index=len(self.bones)
+        self.bones.append(bone)
+        self.boneMap[bone.name]=bone
+
+
+class PmdExporter(object):
+
+    __slots__=[
+            'armatureObj',
+            'oneSkinMesh',
+            'englishName',
+            'englishComment',
+            'name',
+            'comment',
+            'skeleton',
+            ]
+    def setup(self):
+        self.armatureObj=None
+
+        # 木構造を構築する
+        object_node_map={}
+        for o in bl.object.each():
+            object_node_map[o]=Node(o)
+        for o in bl.object.each():
+            node=object_node_map[o]
+            if node.o.parent:
+                object_node_map[node.o.parent].children.append(node)
+
+        # ルートを得る
+        root=object_node_map[bl.object.getActive()]
+        o=root.o
+        self.englishName=o.name
+        self.englishComment=o[MMD_COMMENT] if MMD_COMMENT in o else 'blender export\n'
+        self.name=o[MMD_MB_NAME] if MMD_MB_NAME in o else 'Blenderエクスポート'
+        self.comment=o[MMD_MB_COMMENT] if MMD_MB_COMMENT in o else 'Blnderエクスポート\n'
+
+        # ワンスキンメッシュを作る
+        self.oneSkinMesh=OneSkinMesh()
+        self.__createOneSkinMesh(root)
+        bl.message(self.oneSkinMesh)
+        if len(self.oneSkinMesh.morphList)==0:
+            # create emtpy skin
+            self.oneSkinMesh.createEmptyBasicSkin()
+
+        # skeleton
+        self.skeleton=BoneBuilder()
+        self.skeleton.build(self.armatureObj)
+
+    def __createOneSkinMesh(self, node):
+        ############################################################
+        # search armature modifier
+        ############################################################
+        for m in node.o.modifiers:
+            if bl.modifier.isType(m, 'ARMATURE'):
+                armatureObj=bl.modifier.getArmatureObject(m)
+                if not self.armatureObj:
+                    self.armatureObj=armatureObj
+                elif self.armatureObj!=armatureObj:
+                    print("warning! found multiple armature. ignored.", 
+                            armatureObj.name)
+
+        if node.o.type.upper()=='MESH':
+            self.oneSkinMesh.addMesh(node.o)
+
+        for child in node.children:
+            self.__createOneSkinMesh(child)
+
+    def write(self, path):
+        io=pmd.IO()
+        io.setName(toCP932(self.name))
+        io.setComment(toCP932(self.comment))
+        io.version=1.0
+
+        # 頂点
+        for pos, attribute, b0, b1, weight in self.oneSkinMesh.vertexArray.zip():
+            # convert right-handed z-up to left-handed y-up
+            v=io.addVertex()
+            v.pos.x=pos[0]
+            v.pos.y=pos[2]
+            v.pos.z=pos[1]
+            v.normal.x=attribute.nx
+            v.normal.y=attribute.ny
+            v.normal.z=attribute.nz
+            v.uv.x=attribute.u
+            v.uv.y=1.0-attribute.v # reverse vertical
+            v.bone0=self.skeleton.indexByName(b0)
+            v.bone1=self.skeleton.indexByName(b1)
+            v.weight0=int(100*weight)
+            v.edge_flag=0 # edge flag, 0: enable edge, 1: not edge
+
+        # 面とマテリアル
+        vertexCount=self.oneSkinMesh.getVertexCount()
+        for material_name, indices in self.oneSkinMesh.vertexArray.each():
+            #print('material:', material_name)
+            m=bl.material.get(material_name)
+            # マテリアル
+            material=io.addMaterial()
+            setMaterialParams(material, m)
+
+            material.vertex_count=len(indices)
+            material.toon_index=0
+            textures=[os.path.basename(path) 
+                for path in bl.material.eachEnalbeTexturePath(m)]
+            if len(textures)>0:
+                material.setTexture(toCP932('*'.join(textures)))
+            else:
+                material.setTexture(toCP932(""))
+            # 面
+            for i in indices:
+                assert(i<vertexCount)
+            for i in xrange(0, len(indices), 3):
+                # reverse triangle
+                io.indices.append(indices[i])
+                io.indices.append(indices[i+1])
+                io.indices.append(indices[i+2])
+
+        # bones
+        boneNameMap={}
+        for i, b in enumerate(self.skeleton.bones):
+            bone=io.addBone()
+
+            # name
+            boneNameMap[b.name]=i
+            v=englishmap.getUnicodeBoneName(b.name)
+            if not v:
+                v=[b.name, b.name]
+            assert(v)
+            cp932=v[1].encode('cp932')
+            assert(len(cp932)<20)
+            bone.setName(cp932)
+
+            # english name
+            bone_english_name=toCP932(b.name)
+            assert(len(bone_english_name)<20)
+            bone.setEnglishName(bone_english_name)
+
+            if len(v)>=3:
+                # has type
+                if v[2]==5:
+                    b.ik_index=self.skeleton.indexByName('eyes')
+                bone.type=v[2]
+            else:
+                bone.type=b.type
+
+            bone.parent_index=b.parent_index
+            bone.tail_index=b.tail_index
+            bone.ik_index=b.ik_index
+
+            # convert right-handed z-up to left-handed y-up
+            bone.pos.x=b.pos[0] if not near(b.pos[0], 0) else 0
+            bone.pos.y=b.pos[2] if not near(b.pos[2], 0) else 0
+            bone.pos.z=b.pos[1] if not near(b.pos[1], 0) else 0
+
+        # IK
+        for ik in self.skeleton.ik_list:
+            solver=io.addIK()
+            solver.index=self.skeleton.getIndex(ik.target)
+            solver.target=self.skeleton.getIndex(ik.effector)
+            solver.length=ik.length
+            b=self.skeleton.bones[ik.effector.parent_index]
+            for i in xrange(solver.length):
+                solver.children.append(self.skeleton.getIndex(b))
+                b=self.skeleton.bones[b.parent_index]
+            solver.iterations=ik.iterations
+            solver.weight=ik.weight
+
+        # 表情
+        for i, m in enumerate(self.oneSkinMesh.morphList):
+            # morph
+            morph=io.addMorph()
+
+            v=englishmap.getUnicodeSkinName(m.name)
+            if not v:
+                v=[m.name, m.name, 0]
+            assert(v)
+            cp932=v[1].encode('cp932')
+            morph.setName(cp932)
+            morph.setEnglishName(m.name.encode('cp932'))
+            m.type=v[2]
+            morph.type=v[2]
+            for index, offset in m.offsets:
+                # convert right-handed z-up to left-handed y-up
+                morph.append(index, offset[0], offset[2], offset[1])
+            morph.vertex_count=len(m.offsets)
+
+        # 表情枠
+        # type==0はbase
+        for i, m in enumerate(self.oneSkinMesh.morphList):
+            if m.type==3:
+                io.face_list.append(i)
+        for i, m in enumerate(self.oneSkinMesh.morphList):
+            if m.type==2:
+                io.face_list.append(i)
+        for i, m in enumerate(self.oneSkinMesh.morphList):
+            if m.type==1:
+                io.face_list.append(i)
+        for i, m in enumerate(self.oneSkinMesh.morphList):
+            if m.type==4:
+                io.face_list.append(i)
+
+        # ボーングループ
+        for g in self.skeleton.bone_groups:
+            boneDisplayName=io.addBoneGroup()
+            # name
+            name=englishmap.getUnicodeBoneGroupName(g[0])
+            if not name:
+                name=g[0]
+            boneDisplayName.setName(toCP932(name+'\n'))
+            # english
+            englishName=g[0]
+            boneDisplayName.setEnglishName(toCP932(englishName+'\n'))
+
+        # ボーングループメンバー
+        for i, b in enumerate(self.skeleton.bones):
+            if i==0:
+               continue
+            if b.type in [6, 7]:
+               continue
+            io.addBoneDisplay(i, self.skeleton.getBoneGroup(b))
+
+        #assert(len(io.bones)==len(io.bone_display_list)+1)
+
+        # English
+        io.setEnglishName(toCP932(self.englishName))
+        io.setEnglishComment(toCP932(self.englishComment))
+
+        # toon
+        toonMeshObject=None
+        for o in bl.object.each():
+            try:
+                if o.name.startswith(TOON_TEXTURE_OBJECT):
+                    toonMeshObject=o
+            except:
+                p(o.name)
+            break
+        if toonMeshObject:
+            toonMesh=bl.object.getData(toonMeshObject)
+            toonMaterial=bl.mesh.getMaterial(toonMesh, 0)
+            for i in range(10):
+                t=bl.material.getTexture(toonMaterial, i)
+                if t:
+                    io.getToonTexture(i).setName(toCP932(t.name))
+                else:
+                    io.getToonTexture(i).setName(toCP932("toon%02d.bmp\n" % i))
+        else:
+            for i in range(10):
+                io.getToonTexture(i).setName(toCP932("toon%02d.bmp\n" % i))
+
+        # rigid body
+        rigidNameMap={}
+        for i, obj in enumerate(self.oneSkinMesh.rigidbodies):
+            name=obj[RIGID_NAME] if RIGID_NAME in obj else obj.name
+            print(name)
+            rigidBody=io.addRigidBody()
+            rigidBody.setName(name.encode('cp932'))
+            rigidNameMap[name]=i
+            boneIndex=boneNameMap[obj[RIGID_BONE_NAME]]
+            if boneIndex==0:
+                boneIndex=0xFFFF
+                bone=self.skeleton.bones[0]
+            else:
+                bone=self.skeleton.bones[boneIndex]
+            rigidBody.boneIndex=boneIndex
+            #rigidBody.position.x=obj[RIGID_LOCATION][0]
+            #rigidBody.position.y=obj[RIGID_LOCATION][1]
+            #rigidBody.position.z=obj[RIGID_LOCATION][2]
+            rigidBody.position.x=obj.location.x-bone.pos[0]
+            rigidBody.position.y=obj.location.z-bone.pos[2]
+            rigidBody.position.z=obj.location.y-bone.pos[1]
+            rigidBody.rotation.x=-obj.rotation_euler[0]
+            rigidBody.rotation.y=-obj.rotation_euler[2]
+            rigidBody.rotation.z=-obj.rotation_euler[1]
+            rigidBody.processType=obj[RIGID_PROCESS_TYPE]
+            rigidBody.group=obj[RIGID_GROUP]
+            rigidBody.target=obj[RIGID_INTERSECTION_GROUP]
+            rigidBody.weight=obj[RIGID_WEIGHT]
+            rigidBody.linearDamping=obj[RIGID_LINEAR_DAMPING]
+            rigidBody.angularDamping=obj[RIGID_ANGULAR_DAMPING]
+            rigidBody.restitution=obj[RIGID_RESTITUTION]
+            rigidBody.friction=obj[RIGID_FRICTION]
+            if obj[RIGID_SHAPE_TYPE]==0:
+                rigidBody.shapeType=pmd.SHAPE_SPHERE
+                rigidBody.w=obj.scale[0]
+            elif obj[RIGID_SHAPE_TYPE]==1:
+                rigidBody.shapeType=pmd.SHAPE_BOX
+                rigidBody.w=obj.scale[0]
+                rigidBody.d=obj.scale[1]
+                rigidBody.h=obj.scale[2]
+            elif obj[RIGID_SHAPE_TYPE]==2:
+                rigidBody.shapeType=pmd.SHAPE_CAPSULE
+                rigidBody.w=obj.scale[0]
+                rigidBody.h=obj.scale[2]
+
+        # constraint
+        for obj in self.oneSkinMesh.constraints:
+            constraint=io.addConstraint()
+            constraint.setName(obj[CONSTRAINT_NAME].encode('cp932'))
+            constraint.rigidA=rigidNameMap[obj[CONSTRAINT_A]]
+            constraint.rigidB=rigidNameMap[obj[CONSTRAINT_B]]
+            constraint.pos.x=obj.location[0]
+            constraint.pos.y=obj.location[2]
+            constraint.pos.z=obj.location[1]
+            constraint.rot.x=-obj.rotation_euler[0]
+            constraint.rot.y=-obj.rotation_euler[2]
+            constraint.rot.z=-obj.rotation_euler[1]
+            constraint.constraintPosMin.x=obj[CONSTRAINT_POS_MIN][0]
+            constraint.constraintPosMin.y=obj[CONSTRAINT_POS_MIN][1]
+            constraint.constraintPosMin.z=obj[CONSTRAINT_POS_MIN][2]
+            constraint.constraintPosMax.x=obj[CONSTRAINT_POS_MAX][0]
+            constraint.constraintPosMax.y=obj[CONSTRAINT_POS_MAX][1]
+            constraint.constraintPosMax.z=obj[CONSTRAINT_POS_MAX][2]
+            constraint.constraintRotMin.x=obj[CONSTRAINT_ROT_MIN][0]
+            constraint.constraintRotMin.y=obj[CONSTRAINT_ROT_MIN][1]
+            constraint.constraintRotMin.z=obj[CONSTRAINT_ROT_MIN][2]
+            constraint.constraintRotMax.x=obj[CONSTRAINT_ROT_MAX][0]
+            constraint.constraintRotMax.y=obj[CONSTRAINT_ROT_MAX][1]
+            constraint.constraintRotMax.z=obj[CONSTRAINT_ROT_MAX][2]
+            constraint.springPos.x=obj[CONSTRAINT_SPRING_POS][0]
+            constraint.springPos.y=obj[CONSTRAINT_SPRING_POS][1]
+            constraint.springPos.z=obj[CONSTRAINT_SPRING_POS][2]
+            constraint.springRot.x=obj[CONSTRAINT_SPRING_ROT][0]
+            constraint.springRot.y=obj[CONSTRAINT_SPRING_ROT][1]
+            constraint.springRot.z=obj[CONSTRAINT_SPRING_ROT][2]
+
+        # 書き込み
+        bl.message('write: %s' % path)
+        return io.write(path)
+
+
+def __execute(filename):
+    active=bl.object.getActive()
+    if not active:
+        print("abort. no active object.")
+        return
+    exporter=PmdExporter()
+    exporter.setup()
+    print(exporter)
+    exporter.write(filename)
+    bl.object.activate(active)
+
+
+if isBlender24():
+    # for 2.4
+    def execute_24(filename):
+        bl.initialize('pmd_export', bpy.data.scenes.active)
+        __execute(filename.decode(bl.INTERNAL_ENCODING))
+        bl.finalize()
+
+    Blender.Window.FileSelector(
+             execute_24,
+             'Export Metasequoia PMD',
+             Blender.sys.makename(ext='.pmd'))
+
+else:
+    # for 2.5
+    def execute_25(filename, scene):
+        bl.initialize('pmd_export', scene)
+        __execute(filename)
+        bl.finalize()
+
+    # operator
+    class EXPORT_OT_pmd(bpy.types.Operator):
+        '''Save a Metasequoia PMD file.'''
+        bl_idname = "export_scene.pmd"
+        bl_label = 'Export PMD'
+
+        # List of operator properties, the attributes will be assigned
+        # to the class instance from the operator settings before calling.
+        filepath = bpy.props.StringProperty()
+        filename = bpy.props.StringProperty()
+        directory = bpy.props.StringProperty()
+
+        def execute(self, context):
+            execute_25(
+                    self.properties.filepath, 
+                    context.scene
+                    )
+            return 'FINISHED'
+
+        def invoke(self, context, event):
+            wm=context.window_manager
+            try:
+                wm.fileselect_add(self)
+            except:
+                wm.add_fileselect(self)
+            return 'RUNNING_MODAL'
+
+    # register menu
+    def menu_func(self, context): 
+        default_path=bpy.data.filepath.replace(".blend", ".pmd")
+        self.layout.operator(
+                EXPORT_OT_pmd.bl_idname, 
+                text="Miku Miku Dance Model(.pmd)",
+                icon='PLUGIN'
+                ).filepath=default_path
+
+    def register():
+        bpy.types.INFO_MT_file_export.append(menu_func)
+
+    def unregister():
+        bpy.types.INFO_MT_file_export.remove(menu_func)
+
+    if __name__ == "__main__":
+        register()
+
diff --git a/pymeshio/io_import_scene_mqo.py b/pymeshio/io_import_scene_mqo.py
new file mode 100755 (executable)
index 0000000..e4addea
--- /dev/null
@@ -0,0 +1,722 @@
+#!BPY\r
+# coding: utf-8\r
+""" \r
+Name: 'Metasequoia(.mqo)...'\r
+Blender: 245\r
+Group: 'Import'\r
+Tooltip: 'Import from Metasequoia file format (.mqo)'\r
+"""\r
+__author__=['ousttrue']\r
+__url__ = ["http://gunload.web.fc2.com/blender/"]\r
+__version__= '2.2'\r
+__bpydoc__= '''\\r
+\r
+MQO Importer\r
+\r
+This script imports a mqo into Blender for editing.\r
+\r
+0.2 20080123: update.\r
+0.3 20091125: modify for linux.\r
+0.4 20100310: rewrite.\r
+0.5 20100311: create armature from mikoto bone.\r
+0.6 20100505: C extension.\r
+0.7 20100606: integrate 2.4 and 2.5.\r
+0.8 20100619: fix multibyte object name.\r
+0.9 20100626: refactoring.\r
+2.0 20100724: update for Blender2.53.\r
+2.1 20100731: add full python module.\r
+2.2 20101005: update for Blender2.54.\r
+2.3 20101228: update for Blender2.55.\r
+'''\r
+\r
+bl_addon_info = {\r
+        'category': 'Import/Export',\r
+        'name': 'Import: Metasequioa Model Format (.mqo)',\r
+        'author': 'ousttrue',\r
+        'version': (2, 0),\r
+        'blender': (2, 5, 3),\r
+        'location': 'File > Import',\r
+        'description': 'Import from the Metasequioa Model Format (.mqo)',\r
+        'warning': '', # used for warning icon and text in addons panel\r
+        'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',\r
+        'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',\r
+        }\r
+\r
+import os\r
+import sys\r
+\r
+try:\r
+    # C extension\r
+    from meshio import mqo\r
+    print('use meshio C module')\r
+except ImportError:\r
+    # full python\r
+    from pymeshio import mqo\r
+\r
+def isBlender24():\r
+    return sys.version_info[0]<3\r
+\r
+if isBlender24():\r
+    # for 2.4\r
+    import Blender\r
+    from Blender import Mathutils\r
+    import bpy\r
+\r
+    # wrapper\r
+    import bl24 as bl\r
+\r
+    def createMqoMaterial(m):\r
+        material = Blender.Material.New(\r
+                m.getName().encode(bl.INTERNAL_ENCODING))\r
+        #material.mode |= Blender.Material.Modes.SHADELESS\r
+        # diffuse\r
+        material.rgbCol = [m.color.r, m.color.g, m.color.b]\r
+        material.alpha = m.color.a\r
+        # other\r
+        material.amb=m.ambient\r
+        material.spec=m.specular\r
+        material.hard=int(255 * m.power)\r
+        material.emit=m.emit\r
+        return material\r
+\r
+else:\r
+    # for 2.5\r
+    import bpy\r
+\r
+    # wrapper\r
+    import bl25 as bl\r
+\r
+    def createMqoMaterial(m):\r
+        material = bpy.data.materials.new(m.getName())\r
+        # shader\r
+        if m.shader==1:\r
+            material.diffuse_shader='FRESNEL'\r
+        else:\r
+            material.diffuse_shader='LAMBERT'\r
+        # diffuse\r
+        material.diffuse_color=[m.color.r, m.color.g, m.color.b]\r
+        material.diffuse_intensity=m.diffuse\r
+        material.alpha=m.color.a\r
+        # other\r
+        material.ambient = m.ambient\r
+        #material.specular = m.specular\r
+        material.emit=m.emit\r
+        material.use_shadeless=True\r
+        return material\r
+\r
+\r
+def has_mikoto(mqo):\r
+    #for o in mqo.objects:\r
+    #    if o.getName().startswith('bone'):\r
+    #        return True\r
+    #    if o.getName().startswith('sdef'):\r
+    #        return True\r
+    #    if o.getName().startswith('anchor'):\r
+    #        return True\r
+    return False\r
+\r
+\r
+def __createMaterials(mqo, directory):\r
+    """\r
+    create blender materials and renturn material list.\r
+    """\r
+    materials = []\r
+    textureMap={}\r
+    imageMap={}\r
+    if len(mqo.materials)>0:\r
+        for material_index, m in enumerate(mqo.materials):\r
+            # material\r
+            material=createMqoMaterial(m)\r
+            materials.append(material)\r
+            # texture\r
+            texture_name=m.getTexture()\r
+            if texture_name!='':\r
+                if texture_name in textureMap:\r
+                    texture=textureMap[texture_name]\r
+                else:\r
+                    # load texture image\r
+                    if os.path.isabs(texture_name):\r
+                        # absolute\r
+                        path = texture_name\r
+                    else:\r
+                        # relative\r
+                        path = os.path.join(directory, texture_name)\r
+                    # texture\r
+                    path=path.replace("\\", "/")\r
+                    if os.path.exists(path):\r
+                        print("create texture:", path)\r
+                        texture, image=bl.texture.create(path)\r
+                        textureMap[texture_name]=texture\r
+                        imageMap[material_index]=image\r
+                    else:\r
+                        print("%s not exits" % path)\r
+                        continue\r
+                bl.material.addTexture(material, texture)\r
+    else:\r
+        # default material\r
+        pass\r
+    return materials, imageMap\r
+\r
+\r
+def __createObjects(mqo, root, materials, imageMap, scale):\r
+    """\r
+    create blender mesh objects.\r
+    """\r
+    # tree stack\r
+    stack=[root]    \r
+    objects=[]\r
+    for o in mqo.objects:\r
+        mesh, mesh_object=bl.mesh.create(o.getName())\r
+\r
+        # add hierarchy\r
+        stack_depth=len(stack)-1\r
+        #print(o.depth, stack_depth)\r
+        if o.depth<stack_depth:\r
+            for i in range(stack_depth-o.depth):\r
+                stack.pop()\r
+        bl.object.makeParent(stack[-1], mesh_object)\r
+        stack.append(mesh_object)\r
+\r
+        if o.getName().startswith('sdef'):\r
+            objects.append(mesh_object)\r
+        elif o.getName().startswith('anchor'):\r
+            bl.object.setLayerMask(mesh_object, [0, 1])\r
+        elif o.getName().startswith('bone'):\r
+            bl.object.setLayerMask(mesh_object, [0, 1])\r
+\r
+        # geometry\r
+        vertices=[(v.x * scale, -v.z * scale, v.y * scale) for v in o.vertices]\r
+        faces=[]\r
+        materialMap={}\r
+        for f in o.faces:\r
+            face_indices=[]\r
+            # flip face\r
+            for i in reversed(range(f.index_count)):\r
+                face_indices.append(f.getIndex(i))\r
+            faces.append(face_indices)\r
+            materialMap[f.material_index]=True\r
+        bl.mesh.addGeometry(mesh, vertices, faces)\r
+\r
+        # blender limits 16 materials per mesh\r
+        for i, material_index in enumerate(materialMap.keys()):\r
+            if i>=16:\r
+                # split a mesh ?\r
+                print("over 16 materials!")\r
+                break\r
+            bl.mesh.addMaterial(mesh, materials[material_index])\r
+            materialMap[material_index]=i\r
\r
+        # set face params\r
+        assert(len(o.faces)==len(mesh.faces))\r
+        bl.mesh.addUV(mesh)\r
+        for i, (f, face) in enumerate(zip(o.faces, mesh.faces)):\r
+            uv_array=[]\r
+            # ToDo FIX\r
+            # flip face\r
+            for j in reversed(range(f.index_count)):\r
+                uv_array.append((f.getUV(j).x, 1.0-f.getUV(j).y))\r
+            bl.mesh.setFaceUV(mesh, i, face, uv_array, \r
+                    imageMap.get(f.material_index, None))\r
+            if f.material_index in materialMap:\r
+                bl.face.setMaterial(face, materialMap[f.material_index])\r
+            bl.face.setSmooth(face, True)\r
+\r
+        # mirror modifier\r
+        if o.mirror:\r
+            bl.modifier.addMirror(mesh_object)\r
+\r
+        # set smoothing\r
+        bl.mesh.setSmooth(mesh, o.smoothing)\r
+\r
+        # calc normal\r
+        bl.mesh.recalcNormals(mesh_object)\r
+\r
+    return objects\r
+\r
+\r
+###############################################################################\r
+# for mqo mikoto bone.\r
+###############################################################################\r
+class MikotoBone(object):\r
+    __slots__=[\r
+            'name',\r
+            'iHead', 'iTail', 'iUp',\r
+            'vHead', 'vTail', 'vUp',\r
+            'parent', 'isFloating',\r
+            'children',\r
+            ]\r
+    def __init__(self, face=None, vertices=None, materials=None):\r
+        self.parent=None\r
+        self.isFloating=False\r
+        self.children=[]\r
+        if not face:\r
+            self.name='root'\r
+            return\r
+\r
+        self.name=materials[face.material_index].name.encode('utf-8')\r
+\r
+        i0=face.getIndex(0)\r
+        i1=face.getIndex(1)\r
+        i2=face.getIndex(2)\r
+        v0=vertices[i0]\r
+        v1=vertices[i1]\r
+        v2=vertices[i2]\r
+        e01=v1-v0\r
+        e12=v2-v1\r
+        e20=v0-v2\r
+        sqNorm0=e01.getSqNorm()\r
+        sqNorm1=e12.getSqNorm()\r
+        sqNorm2=e20.getSqNorm()\r
+        if sqNorm0>sqNorm1:\r
+            if sqNorm1>sqNorm2:\r
+                # e01 > e12 > e20\r
+                self.iHead=i2\r
+                self.iTail=i1\r
+                self.iUp=i0\r
+            else:\r
+                if sqNorm0>sqNorm2:\r
+                    # e01 > e20 > e12\r
+                    self.iHead=i2\r
+                    self.iTail=i0\r
+                    self.iUp=i1\r
+                else:\r
+                    # e20 > e01 > e12\r
+                    self.iHead=i1\r
+                    self.iTail=i0\r
+                    self.iUp=i2\r
+        else:\r
+            # 0 < 1\r
+            if sqNorm1<sqNorm2:\r
+                # e20 > e12 > e01\r
+                self.iHead=i1\r
+                self.iTail=i2\r
+                self.iUp=i0\r
+            else:\r
+                if sqNorm0<sqNorm2:\r
+                    # e12 > e20 > e01\r
+                    self.iHead=i0\r
+                    self.iTail=i2\r
+                    self.iUp=i1\r
+                else:\r
+                    # e12 > e01 > e20\r
+                    self.iHead=i0\r
+                    self.iTail=i1\r
+                    self.iUp=i2\r
+        self.vHead=vertices[self.iHead]\r
+        self.vTail=vertices[self.iTail]\r
+        self.vUp=vertices[self.iUp]\r
+\r
+        if self.name.endswith('[]'):\r
+            basename=self.name[0:-2]\r
+            # expand LR name\r
+            if self.vTail.x>0:\r
+                self.name="%s_L" % basename\r
+            else:\r
+                self.name="%s_R" % basename\r
+\r
+\r
+    def setParent(self, parent, floating=False):\r
+        if floating:\r
+            self.isFloating=True\r
+        self.parent=parent\r
+        parent.children.append(self)\r
+\r
+    def printTree(self, indent=''):\r
+        print("%s%s" % (indent, self.name))\r
+        for child in self.children:\r
+            child.printTree(indent+'  ')\r
+\r
+\r
+def build_armature(armature, mikotoBone, parent=None):\r
+    """\r
+    create a armature bone.\r
+    """\r
+    bone = Armature.Editbone()\r
+    bone.name = mikotoBone.name.encode('utf-8')\r
+    armature.bones[bone.name] = bone\r
+\r
+    bone.head = Mathutils.Vector(*mikotoBone.vHead.to_a())\r
+    bone.tail = Mathutils.Vector(*mikotoBone.vTail.to_a())\r
+    if parent:\r
+        bone.parent=parent\r
+        if mikotoBone.isFloating:\r
+            pass\r
+        else:\r
+            bone.options=[Armature.CONNECTED]\r
+\r
+    for child in mikotoBone.children:\r
+        build_armature(armature, child, bone)\r
+\r
+\r
+def create_armature(mqo):\r
+    """\r
+    create armature\r
+    """\r
+    boneObject=None\r
+    for o in mqo.objects:\r
+        if o.name.startswith('bone'):\r
+            boneObject=o\r
+            break\r
+    if not boneObject:\r
+        return\r
+\r
+    tailMap={}\r
+    for f in boneObject.faces:\r
+        if f.index_count!=3:\r
+            print("invalid index_count: %d" % f.index_count)\r
+            continue\r
+        b=MikotoBone(f, boneObject.vertices, mqo.materials)\r
+        tailMap[b.iTail]=b\r
+\r
+    #################### \r
+    # build mikoto bone tree\r
+    #################### \r
+    mikotoRoot=MikotoBone()\r
+\r
+    for b in tailMap.values():\r
+        # each bone has unique parent or is root bone.\r
+        if b.iHead in tailMap:\r
+            b.setParent(tailMap[b.iHead])\r
+        else: \r
+            isFloating=False\r
+            for e in boneObject.edges:\r
+                if  b.iHead==e.indices[0]:\r
+                    # floating bone\r
+                    if e.indices[1] in tailMap:\r
+                        b.setParent(tailMap[e.indices[1]], True)\r
+                        isFloating=True\r
+                        break\r
+                elif b.iHead==e.indices[1]:\r
+                    # floating bone\r
+                    if e.indices[0] in tailMap:\r
+                        b.setParent(tailMap[e.indices[0]], True)\r
+                        isFloating=True\r
+                        break\r
+            if isFloating:\r
+                continue\r
+\r
+            # no parent bone\r
+            b.setParent(mikotoRoot, True)\r
+\r
+    if len(mikotoRoot.children)==0:\r
+        print("no root bone")\r
+        return\r
+\r
+    if len(mikotoRoot.children)==1:\r
+        # single root\r
+        mikotoRoot=mikotoRoot.children[0]\r
+        mikotoRoot.parent=None\r
+    else:\r
+        mikotoRoot.vHead=Vector3(0, 10, 0)\r
+        mikotoRoot.vTail=Vector3(0, 0, 0)\r
+\r
+    #################### \r
+    # create armature\r
+    #################### \r
+    armature = Armature.New()\r
+    # link to object\r
+    armature_object = scene.objects.new(armature)\r
+    # create action\r
+    act = Armature.NLA.NewAction()\r
+    act.setActive(armature_object)\r
+    # set XRAY\r
+    armature_object.drawMode |= Object.DrawModes.XRAY\r
+    # armature settings\r
+    armature.drawType = Armature.OCTAHEDRON\r
+    armature.envelopes = False\r
+    armature.vertexGroups = True\r
+    armature.mirrorEdit = True\r
+    armature.drawNames=True\r
+\r
+    # edit bones\r
+    armature.makeEditable()\r
+    build_armature(armature, mikotoRoot)\r
+    armature.update()\r
+\r
+    return armature_object\r
+        \r
+\r
+class TrianglePlane(object):\r
+    """\r
+    mikoto\e$BJ}<0%\!<%s$N%"%s%+!<%&%'%$%H7W;;MQ!#\e(B\r
+    (\e$BIT40A4\e(B)\r
+    """\r
+    __slots__=['normal', \r
+            'v0', 'v1', 'v2',\r
+            ]\r
+    def __init__(self, v0, v1, v2):\r
+        self.v0=v0\r
+        self.v1=v1\r
+        self.v2=v2\r
+\r
+    def isInsideXY(self, p):\r
+        v0=Vector2(self.v0.x, self.v0.y)\r
+        v1=Vector2(self.v1.x, self.v1.y)\r
+        v2=Vector2(self.v2.x, self.v2.y)\r
+        e01=v1-v0\r
+        e12=v2-v1\r
+        e20=v0-v2\r
+        c0=Vector2.cross(e01, p-v0)\r
+        c1=Vector2.cross(e12, p-v1)\r
+        c2=Vector2.cross(e20, p-v2)\r
+        if c0>=0 and c1>=0 and c2>=0:\r
+            return True\r
+        if c0<=0 and c1<=0 and c2<=0:\r
+            return True\r
+\r
+    def isInsideYZ(self, p):\r
+        v0=Vector2(self.v0.y, self.v0.z)\r
+        v1=Vector2(self.v1.y, self.v1.z)\r
+        v2=Vector2(self.v2.y, self.v2.z)\r
+        e01=v1-v0\r
+        e12=v2-v1\r
+        e20=v0-v2\r
+        c0=Vector2.cross(e01, p-v0)\r
+        c1=Vector2.cross(e12, p-v1)\r
+        c2=Vector2.cross(e20, p-v2)\r
+        if c0>=0 and c1>=0 and c2>=0:\r
+            return True\r
+        if c0<=0 and c1<=0 and c2<=0:\r
+            return True\r
+\r
+    def isInsideZX(self, p):\r
+        v0=Vector2(self.v0.z, self.v0.x)\r
+        v1=Vector2(self.v1.z, self.v1.x)\r
+        v2=Vector2(self.v2.z, self.v2.x)\r
+        e01=v1-v0\r
+        e12=v2-v1\r
+        e20=v0-v2\r
+        c0=Vector2.cross(e01, p-v0)\r
+        c1=Vector2.cross(e12, p-v1)\r
+        c2=Vector2.cross(e20, p-v2)\r
+        if c0>=0 and c1>=0 and c2>=0:\r
+            return True\r
+        if c0<=0 and c1<=0 and c2<=0:\r
+            return True\r
+\r
+\r
+class MikotoAnchor(object):\r
+    """\r
+    mikoto\e$BJ}<0%9%1%k%H%s$N%"%s%+!<!#\e(B\r
+    """\r
+    __slots__=[\r
+            "triangles", "bbox",\r
+            ]\r
+    def __init__(self):\r
+        self.triangles=[]\r
+        self.bbox=None\r
+\r
+    def push(self, face, vertices):\r
+        if face.index_count==3:\r
+            self.triangles.append(TrianglePlane(\r
+                vertices[face.indices[0]],\r
+                vertices[face.indices[1]],\r
+                vertices[face.indices[2]]\r
+                ))\r
+        elif face.index_count==4:\r
+            self.triangles.append(TrianglePlane(\r
+                vertices[face.indices[0]],\r
+                vertices[face.indices[1]],\r
+                vertices[face.indices[2]]\r
+                ))\r
+            self.triangles.append(TrianglePlane(\r
+                vertices[face.indices[2]],\r
+                vertices[face.indices[3]],\r
+                vertices[face.indices[0]]\r
+                ))\r
+        # bounding box\r
+        if not self.bbox:\r
+            self.bbox=BoundingBox(vertices[face.indices[0]])\r
+        for i in face.indices:\r
+            self.bbox.expand(vertices[i])\r
+\r
+\r
+    def calcWeight(self, v):\r
+        if not self.bbox.isInside(v):\r
+            return 0\r
+\r
+        if self.anyXY(v.x, v.y) and self.anyYZ(v.y, v.z) and self.anyZX(v.z, v.x):\r
+            return 1.0\r
+        else:\r
+            return 0\r
+        \r
+    def anyXY(self, x, y):\r
+        for t in self.triangles:\r
+            if t.isInsideXY(Vector2(x, y)):\r
+                return True\r
+        return False\r
+\r
+    def anyYZ(self, y, z):\r
+        for t in self.triangles:\r
+            if t.isInsideYZ(Vector2(y, z)):\r
+                return True\r
+        return False\r
+\r
+    def anyZX(self, z, x):\r
+        for t in self.triangles:\r
+            if t.isInsideZX(Vector2(z, x)):\r
+                return True\r
+        return False\r
+\r
+\r
+def create_bone_weight(scene, mqo, armature_object, objects):\r
+    """\r
+    create mikoto bone weight.\r
+    """\r
+    anchorMap={}\r
+    # setup mikoto anchors\r
+    for o in mqo.objects:\r
+        if o.name.startswith("anchor"):\r
+            for f in o.faces:\r
+                name=mqo.materials[f.material_index].name\r
+                if name.endswith('[]'):\r
+                    basename=name[0:-2]\r
+                    v=o.vertices[f.indices[0]]\r
+                    if(v.x>0):\r
+                        # L\r
+                        name_L=basename+'_L'\r
+                        if not name_L in anchorMap:\r
+                            anchorMap[name_L]=MikotoAnchor()\r
+                        anchorMap[name_L].push(f, o.vertices)\r
+                    elif(v.x<0):\r
+                        # R\r
+                        name_R=basename+'_R'\r
+                        if not name_R in anchorMap:\r
+                            anchorMap[name_R]=MikotoAnchor()\r
+                        anchorMap[name_R].push(f, o.vertices)\r
+                    else:\r
+                        print("no side", v)\r
+                else:\r
+                    if not name in anchorMap:\r
+                        anchorMap[name]=MikotoAnchor()\r
+                    anchorMap[name].push(f, o.vertices)\r
+\r
+    for o in objects:\r
+        # add armature modifier\r
+        mod=o.modifiers.append(Modifier.Types.ARMATURE)\r
+        mod[Modifier.Settings.OBJECT] = armature_object\r
+        mod[Modifier.Settings.ENVELOPES] = False\r
+        o.makeDisplayList()\r
+        # create vertex group\r
+        mesh=o.getData(mesh=True)\r
+        for name in anchorMap.keys():\r
+            mesh.addVertGroup(name)\r
+        mesh.update()\r
+                 \r
+    # assing vertices to vertex group\r
+    for o in objects:\r
+        mesh=o.getData(mesh=True)\r
+        for i, mvert in enumerate(mesh.verts):\r
+            hasWeight=False\r
+            for name, anchor in anchorMap.items():\r
+                weight=anchor.calcWeight(mvert.co)\r
+                if weight>0:\r
+                    mesh.assignVertsToGroup(\r
+                            name, [i], weight, Mesh.AssignModes.ADD)\r
+                    hasWeight=True\r
+            if not hasWeight:\r
+                # debug orphan vertex\r
+                print('orphan', mvert)\r
+        mesh.update()\r
+\r
+\r
+def __execute(filename, scene, scale=0.1):\r
+    # parse file\r
+    io=mqo.IO()\r
+    if not io.read(filename):\r
+        bl.message("fail to load %s" % filename)\r
+        return\r
+\r
+    # create materials\r
+    materials, imageMap=__createMaterials(io, os.path.dirname(filename))\r
+    if len(materials)==0:\r
+        materials.append(bl.material.create('default'))\r
+\r
+    # create objects\r
+    root=bl.object.createEmpty(os.path.basename(filename))\r
+    objects=__createObjects(io, root, materials, imageMap, scale)\r
+\r
+    if has_mikoto(io):\r
+        # create mikoto bone\r
+        armature_object=create_armature(io)\r
+        if armature_object:\r
+            root.makeParent([armature_object])\r
+\r
+            # create bone weight\r
+            create_bone_weight(io, armature_object, objects)\r
+\r
\r
+###############################################################################\r
+# register\r
+###############################################################################\r
+if isBlender24():\r
+    # for 2.4\r
+    def execute_24(filename):\r
+        scene=Blender.Scene.GetCurrent()\r
+        bl.initialize('mqo_import', scene)\r
+        __execute(\r
+                filename.decode(bl.INTERNAL_ENCODING), \r
+                scene)\r
+        bl.finalize()\r
+\r
+    # execute\r
+    Blender.Window.FileSelector(execute_24, 'Import MQO', '*.mqo')\r
+\r
+else:\r
+    # for 2.5\r
+    def execute_25(filename, scene, scale):\r
+        bl.initialize('mqo_import', scene)\r
+        __execute(filename, scene, scale)\r
+        bl.finalize()\r
+\r
+    # operator\r
+    class IMPORT_OT_mqo(bpy.types.Operator):\r
+        '''Import from Metasequoia file format (.mqo)'''\r
+        bl_idname = "import_scene.mqo"\r
+        bl_label = 'Import MQO'\r
+\r
+        # List of operator properties, the attributes will be assigned\r
+        # to the class instance from the operator settings before calling.\r
+        filepath = bpy.props.StringProperty()\r
+        filename = bpy.props.StringProperty()\r
+        directory = bpy.props.StringProperty()\r
+\r
+        scale = bpy.props.FloatProperty(\r
+                name="Scale", \r
+                description="Scale the MQO by this value", \r
+                min=0.0001, max=1000000.0, \r
+                soft_min=0.001, soft_max=100.0, default=0.1)\r
+\r
+        def execute(self, context):\r
+            execute_25(\r
+                    self.properties.filepath, \r
+                    context.scene, \r
+                    self.properties.scale)\r
+            return 'FINISHED'\r
+\r
+        def invoke(self, context, event):\r
+            wm=context.window_manager\r
+            try:\r
+                wm.fileselect_add(self)\r
+            except:\r
+                wm.add_fileselect(self)\r
+            return 'RUNNING_MODAL'\r
+\r
+\r
+    # register menu\r
+    def menu_func(self, context): \r
+        self.layout.operator(\r
+                IMPORT_OT_mqo.bl_idname, \r
+                text="Metasequoia (.mqo)",\r
+                icon='PLUGIN'\r
+                )\r
+\r
+    def register():\r
+        bpy.types.INFO_MT_file_import.append(menu_func)\r
+\r
+    def unregister():\r
+        bpy.types.INFO_MT_file_import.remove(menu_func)\r
+\r
+    if __name__=="__main__":\r
+        register()\r
+\r
diff --git a/pymeshio/io_import_scene_pmd.py b/pymeshio/io_import_scene_pmd.py
new file mode 100755 (executable)
index 0000000..14c056d
--- /dev/null
@@ -0,0 +1,950 @@
+#!BPY
+# coding:utf-8
+"""
+ Name: 'MikuMikuDance model (.pmd)...'
+ Blender: 248
+ Group: 'Import'
+ Tooltip: 'Import PMD file for MikuMikuDance.'
+"""
+__author__= ["ousttrue"]
+__version__= "2.2"
+__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.
+1.2 20100616: implement rigid body.
+1.3 20100619: fix for various models.
+1.4 20100623: fix constraint name.
+1.5 20100626: refactoring.
+1.6 20100629: sphere map.
+1.7 20100703: implement bone group.
+1.8 20100710: implement toon texture.
+1.9 20100718: keep model name, comment.
+2.0 20100724: update for Blender2.53.
+2.1 20100731: add full python module.
+2.2 20101005: update for Blender2.54.
+2.3 20101228: update for Blender2.55.
+"""
+bl_addon_info = {
+        'category': 'Import/Export',
+        'name': 'Import: MikuMikuDance Model Format (.pmd)',
+        'author': 'ousttrue',
+        'version': (2, 2),
+        'blender': (2, 5, 3),
+        'location': 'File > Import',
+        'description': 'Import from the MikuMikuDance Model Format (.pmd)',
+        'warning': '', # used for warning icon and text in addons panel
+        'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
+        'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',
+        }
+
+MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
+MMD_MB_NAME='mb_name'
+MMD_MB_COMMENT='mb_comment'
+MMD_COMMENT='comment'
+BASE_SHAPE_NAME='Basis'
+RIGID_NAME='rigid_name'
+RIGID_SHAPE_TYPE='rigid_shape_type'
+RIGID_PROCESS_TYPE='rigid_process_type'
+RIGID_BONE_NAME='rigid_bone_name'
+#RIGID_LOCATION='rigid_loation'
+RIGID_GROUP='ribid_group'
+RIGID_INTERSECTION_GROUP='rigid_intersection_group'
+RIGID_WEIGHT='rigid_weight'
+RIGID_LINEAR_DAMPING='rigid_linear_damping'
+RIGID_ANGULAR_DAMPING='rigid_angular_damping'
+RIGID_RESTITUTION='rigid_restitution'
+RIGID_FRICTION='rigid_friction'
+CONSTRAINT_NAME='constraint_name'
+CONSTRAINT_A='const_a'
+CONSTRAINT_B='const_b'
+CONSTRAINT_POS_MIN='const_pos_min'
+CONSTRAINT_POS_MAX='const_pos_max'
+CONSTRAINT_ROT_MIN='const_rot_min'
+CONSTRAINT_ROT_MAX='const_rot_max'
+CONSTRAINT_SPRING_POS='const_spring_pos'
+CONSTRAINT_SPRING_ROT='const_spring_rot'
+TOON_TEXTURE_OBJECT='ToonTextures'
+
+
+###############################################################################
+# import
+###############################################################################
+import os
+import sys
+import math
+
+try:
+    # C extension
+    from meshio import pmd, englishmap
+    print('use meshio C module')
+except ImportError:
+    # full python
+    from pymeshio import englishmap
+    from pymeshio import mmd as pmd
+    pmd.IO=pmd.PMDLoader
+
+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
+
+    def createPmdMaterial(m, index):
+        material=Blender.Material.New()
+        # fresnelが無いw
+        material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
+        material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
+        material.setAlpha(m.diffuse.a)
+        # specular
+        material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
+        material.setSpec(m.shinness*0.1)
+        material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
+        # ambient
+        material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
+        # flag
+        material.enableSSS=True if m.flag==1 else False
+        # name
+        material.name="m_%02d" % index
+        return material
+
+    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
+
+    def setSphereMap(material, index, blend_type='MULTIPLY'):
+        slot=material.textures[index]
+        slot.mapto=Blender.Texture.MapTo.NOR
+        slot.mapping=Blender.Texture.Mappings.SPHERE
+        if blend_type=='MULTIPLY':
+            slot.blendmode=Blender.Texture.BlendModes.MULTIPLY
+        elif blend_type=='ADD':
+            slot.blendmode=Blender.Texture.BlendModes.ADD
+
+else:
+    # for 2.5
+    import bpy
+    import mathutils
+
+    # wrapper
+    import bl25 as bl
+
+    xrange=range
+
+    def createPmdMaterial(m, index):
+        material = bpy.data.materials.new("Material")
+        # diffuse
+        material.diffuse_shader='FRESNEL'
+        material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
+        material.alpha=m.diffuse.a
+        # specular
+        material.specular_shader='TOON'
+        material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
+        material.specular_toon_size=int(m.shinness)
+        # ambient
+        material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
+        # flag
+        material.subsurface_scattering.use=True if m.flag==1 else False
+        # other
+        material.name="m_%02d" % index
+        material.preview_render_type='FLAT'
+        material.use_transparency=True
+        return material
+
+    def poseBoneLimit(n, b):
+        if n.endswith("_t"):
+            return
+        if n.startswith("knee_"):
+            b.lock_ik_y=True
+            b.lock_ik_z=True
+            b.lock_ik_x=False
+            # IK limit
+            b.use_ik_limit_x=True
+            b.ik_min_x=0
+            b.ik_max_x=180
+        elif n.startswith("ankle_"):
+            #b.ik_dof_y=False
+            pass
+
+    def setSphereMap(material, index, blend_type='MULTIPLY'):
+        slot=material.texture_slots[index]
+        slot.texture_coords='NORMAL'
+        slot.mapping='SPHERE'
+        slot.blend_type=blend_type
+
+
+###############################################################################
+def VtoV(v):
+    return bl.createVector(v.x, v.y, v.z)
+
+
+def convert_coord(pos):
+    """
+    Left handed y-up to Right handed z-up
+    """
+    return (pos.x, pos.z, pos.y)
+
+
+def to_radian(degree):
+    return math.pi * degree / 180
+
+
+def get_bone_name(l, index):
+    if index==0xFFFF:
+        return l.bones[0].getName()
+
+    if index < len(l.bones):
+        name=englishmap.getEnglishBoneName(l.bones[index].getName())
+        if name:
+            return name
+        return l.bones[index].getName()
+    print('invalid bone index', index)
+    return l.bones[0].getName()
+
+
+def get_group_name(g):
+    group_name=englishmap.getEnglishBoneGroupName(g.getName().strip())
+    if not group_name:
+        group_name=g.getName().strip()
+    return group_name
+
+
+def __importToonTextures(io, tex_dir):
+    mesh, meshObject=bl.mesh.create(TOON_TEXTURE_OBJECT)
+    material=bl.material.create(TOON_TEXTURE_OBJECT)
+    bl.mesh.addMaterial(mesh, material)
+    for i in range(10):
+        t=io.getToonTexture(i)
+        path=os.path.join(tex_dir, t.getName())
+        texture, image=bl.texture.create(path)
+        bl.material.addTexture(material, texture, False)
+    return meshObject, material
+
+
+def __importShape(obj, l, vertex_map):
+    if len(l.morph_list)==0:
+        return
+
+    # set shape_key pin
+    bl.object.pinShape(obj, True)
+
+    # find base 
+    base=None
+    for s in l.morph_list:
+        if s.type==0:
+            base=s
+
+            # create vertex group
+            bl.object.addVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
+            hasShape=False
+            for i in s.indices:
+                if i in vertex_map:
+                    hasShape=True
+                    bl.object.assignVertexGroup(
+                            obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
+            if not hasShape:
+                return
+    assert(base)
+
+    # create base key
+    baseShapeBlock=bl.object.addShapeKey(obj, BASE_SHAPE_NAME)
+    # mesh
+    mesh=bl.object.getData(obj)
+    mesh.update()
+
+    # each skin
+    for s in l.morph_list:
+        if s.type==0:
+            continue
+
+        # name
+        name=englishmap.getEnglishSkinName(s.getName())
+        if not name:
+            name=s.getName()
+
+        if isBlender24():
+            # 24
+            for index, offset in zip(s.indices, s.pos_list):
+                try:
+                    vertex_index=vertex_map[base.indices[index]]
+                    v=mesh.vertices[vertex_index].co
+                    offset=convert_coord(offset)
+                    v[0]+=offset[0]
+                    v[1]+=offset[1]
+                    v[2]+=offset[2]
+                except IndexError as msg:
+                    print(msg)
+                    print(index, len(base.indices), len(vertex_map))
+                    print(len(mesh.vertices))
+                    print(base.indices[index])
+                    print(vertex_index)
+                    break
+                except KeyError:
+                    #print 'this mesh not has shape vertices'
+                    break
+
+            # create shapekey block
+            new_shape_key=bl.object.addShapeKey(obj, name)
+
+            # copy vertex to shape key
+            mesh.update()
+            
+            # restore
+            for mv, v in zip(mesh.vertices, baseShapeBlock.getData()):
+                mv.co[0] = v[0]
+                mv.co[1] = v[1]
+                mv.co[2] = v[2]
+            mesh.update()
+
+        else:
+            # 25
+            new_shape_key=bl.object.addShapeKey(obj, name)
+
+            for index, offset in zip(s.indices, s.pos_list):
+                try:
+                    vertex_index=vertex_map[base.indices[index]]
+                    bl.shapekey.assign(new_shape_key, vertex_index,
+                            mesh.vertices[vertex_index].co+
+                            bl.createVector(*convert_coord(offset)))
+                except IndexError as msg:
+                    print(msg)
+                    print(index, len(base.indices), len(vertex_map))
+                    print(len(mesh.vertices))
+                    print(base.indices[index])
+                    print(vertex_index)
+                    break
+                except KeyError:
+                    #print 'this mesh not has shape vertices'
+                    break
+
+    # select base shape
+    bl.object.setActivateShapeKey(obj, 0)
+
+
+def __build(armature, b, p, parent):
+    name=englishmap.getEnglishBoneName(b.getName())
+    if not name:
+        name=b.getName()
+
+    bone=bl.armature.createBone(armature, name)
+
+    if parent and (b.tail_index==0 or b.type==6 or b.type==7 or b.type==9):
+        # 先端ボーン
+        bone.head = bl.createVector(*convert_coord(b.pos))
+        bone.tail=bone.head+bl.createVector(0, 1, 0)
+        bone.parent=parent
+        if bone.name=="center_t":
+            # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
+            parent.tail=parent.head+bl.createVector(0, 1, 0)
+            bone.head=parent.tail
+            bone.tail=bone.head+bl.createVector(0, 1, 0)
+        else:
+            if parent.tail==bone.head:
+                pass
+            else:
+                print('diffurence with parent.tail and head', name)
+
+        if b.type!=9:
+            bl.bone.setConnected(bone)
+        # armature layer 2
+        bl.bone.setLayerMask(bone, [0, 1])
+    else:
+        # 通常ボーン
+        bone.head = bl.createVector(*convert_coord(b.pos))
+        bone.tail = bl.createVector(*convert_coord(b.tail))
+        if parent:
+            bone.parent=parent
+            if parent.tail==bone.head:
+                bl.bone.setConnected(bone)
+
+    if bone.head==bone.tail:
+        bone.tail=bone.head+bl.createVector(0, 1, 0)
+
+    for c in b.children:
+        __build(armature, c, b, bone)
+
+
+def __importArmature(l):
+    armature, armature_object=bl.armature.create()
+
+    # build bone
+    bl.armature.makeEditable(armature_object)
+    for b in l.bones:
+        if not b.parent:
+            __build(armature, b, None, None)
+    bl.armature.update(armature)
+    bl.enterObjectMode()
+
+    # IK constraint
+    pose = bl.object.getPose(armature_object)
+    for ik in l.ik_list:
+        target=l.bones[ik.target]
+        name = englishmap.getEnglishBoneName(target.getName())
+        if not name:
+            name=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
+        effector_name=englishmap.getEnglishBoneName(
+                l.bones[ik.index].getName())
+        if not effector_name:
+            effector_name=l.bones[ik.index].getName()
+
+        constraint=bl.armature.createIkConstraint(armature_object, 
+                p_bone, effector_name, ik)
+
+    bl.armature.makeEditable(armature_object)
+    bl.armature.update(armature)
+    bl.enterObjectMode()
+
+    if isBlender24():
+        pass
+    else:
+        # create bone group
+        for i, g in enumerate(l.bone_group_list):
+            name=get_group_name(g)
+            bl.object.createBoneGroup(armature_object, name, "THEME%02d" % (i+1))
+
+        # assign bone to group
+        for b_index, g_index in l.bone_display_list:
+            # bone
+            b=l.bones[b_index]
+            bone_name=englishmap.getEnglishBoneName(b.getName())
+            if not bone_name:
+                bone_name=b.getName()
+            # group
+            g=l.bone_group_list[g_index-1]
+            group_name=get_group_name(g)
+
+            # assign
+            pose.bones[bone_name].bone_group=pose.bone_groups[group_name]
+
+        bl.enterObjectMode()
+
+    return armature_object
+        
+
+def __import16MaerialAndMesh(meshObject, l, 
+        material_order, face_map, tex_dir, toon_material):
+
+    mesh=bl.object.getData(meshObject)
+    ############################################################
+    # material
+    ############################################################
+    bl.progress_print('create materials')
+    mesh_material_map={}
+    textureMap={}
+    imageMap={}
+    index=0
+
+    for material_index in material_order:
+        try:
+            m=l.materials[material_index]
+            mesh_material_map[material_index]=index
+        except KeyError:
+            break
+
+        material=createPmdMaterial(m, material_index)
+
+        # main texture
+        texture_name=m.getTexture()
+        if texture_name!='':
+            for i, t in enumerate(texture_name.split('*')):
+                if t in textureMap:
+                    texture=textureMap[t]
+                else:
+                    path=os.path.join(tex_dir, t)
+                    texture, image=bl.texture.create(path)
+                    textureMap[texture_name]=texture
+                    imageMap[material_index]=image
+                texture_index=bl.material.addTexture(material, texture)
+                if t.endswith('sph'):
+                    # sphere map
+                    setSphereMap(material, texture_index)
+                elif t.endswith('spa'):
+                    # sphere map
+                    setSphereMap(material, texture_index, 'ADD')
+
+        # toon texture
+        toon_index=bl.material.addTexture(
+                material, 
+                bl.material.getTexture(
+                    toon_material, 
+                    0 if m.toon_index==0xFF else m.toon_index
+                    ),
+                False)
+
+        bl.mesh.addMaterial(mesh, material)
+
+        index+=1
+
+    ############################################################
+    # vertex
+    ############################################################
+    bl.progress_print('create vertices')
+    # create vertices
+    vertices=[]
+    for v in l.each_vertex():
+        vertices.append(convert_coord(v.pos))
+
+    ############################################################
+    # face
+    ############################################################
+    bl.progress_print('create faces')
+    # create faces
+    mesh_face_indices=[]
+    mesh_face_materials=[]
+    used_vertices=set()
+
+    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]
+
+        def degenerate(i0, i1, i2):
+            """
+            縮退しているか?
+            """
+            return i0==i1 or i1==i2 or i2==i0
+
+        for j in xrange(0, len(material_faces), 3):
+            i0=material_faces[j]
+            i1=material_faces[j+1]
+            i2=material_faces[j+2]
+            # flip
+            triangle=[i2, i1, i0]
+            if degenerate(*triangle):
+                continue
+            mesh_face_indices.append(triangle[0:3])
+            mesh_face_materials.append(material_index)
+            used_vertices.add(i0)
+            used_vertices.add(i1)
+            used_vertices.add(i2)
+
+    ############################################################
+    # create vertices & faces
+    ############################################################
+    bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
+
+    ############################################################
+    # vertex bone weight
+    ############################################################
+    # create vertex group
+    vertex_groups={}
+    for v in l.each_vertex():
+        vertex_groups[v.bone0]=True
+        vertex_groups[v.bone1]=True
+    for i in vertex_groups.keys():
+        bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
+
+    # vertex params
+    bl.mesh.useVertexUV(mesh)
+    for i, v, mvert in zip(xrange(len(l.vertices)), 
+        l.each_vertex(), mesh.vertices):
+        # normal, uv
+        bl.vertex.setNormal(mvert, convert_coord(v.normal))
+        # bone weight
+        w1=float(v.weight0)/100.0
+        w2=1.0-w1
+        bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
+            i,  w1)
+        bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
+            i,  w2)
+
+    ############################################################
+    # face params
+    ############################################################
+    used_map={}
+    bl.mesh.addUV(mesh)
+    for i, (face, material_index) in enumerate(
+            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)
+        bl.face.setMaterial(face, index)
+        material=mesh.materials[index]
+        used_map[index]=True
+        if bl.material.hasTexture(material):
+            uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
+            bl.mesh.setFaceUV(mesh, i, face, 
+                    # fix uv
+                    [(uv.x, 1.0-uv.y) for uv in uv_array], 
+                    imageMap.get(index, None))
+
+        # set smooth
+        bl.face.setSmooth(face, True)
+
+    mesh.update()
+
+    ############################################################
+    # clean up not used vertices
+    ############################################################
+    bl.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)
+
+    bl.mesh.vertsDelete(mesh, remove_vertices)
+
+    bl.progress_print('%s created' % mesh.name)
+    return vertex_map
+
+
+def __importMaterialAndMesh(io, tex_dir, toon_material):
+    """
+    @param l[in] mmd.PMDLoader
+    @param filename[in]
+    """
+    ############################################################
+    # shpaeキーで使われるマテリアル優先的に前に並べる
+    ############################################################
+    # shapeキーで使われる頂点インデックスを集める
+    shape_key_used_vertices=set()
+    if len(io.morph_list)>0:
+        # base 
+        base=None
+        for s in io.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 io.indices[i] in shape_key_used_vertices:
+                return True
+
+    material_with_shape=set()
+
+    # 各マテリアルの開始頂点インデックスを記録する
+    face_map={}
+    face_count=0
+    for i, m in enumerate(io.materials):
+        face_map[i]=face_count
+        if isMaterialUsedInShape(face_count, m):
+            material_with_shape.add(i)
+        face_count+=m.vertex_count
+
+    # shapeキーで使われる頂点のあるマテリアル
+    material_with_shape=list(material_with_shape)
+    material_with_shape.sort()
+
+    # shapeキーに使われていないマテリアル
+    material_without_shape=[]
+    for i in range(len(io.materials)):
+        if not i in material_with_shape:
+            material_without_shape.append(i)
+
+    # メッシュの生成
+    def __splitList(l, length):
+        for i in range(0, len(l), length):
+            yield l[i:i+length]
+
+    def __importMeshAndShape(material16, name):
+        mesh, meshObject=bl.mesh.create(name)
+
+        # activate object
+        bl.object.deselectAll()
+        bl.object.activate(meshObject)
+
+        # shapeキーで使われる順に並べなおしたマテリアル16個分の
+        # メッシュを作成する
+        vertex_map=__import16MaerialAndMesh(
+                meshObject, io, material16, face_map, tex_dir, toon_material)
+
+        # crete shape key
+        __importShape(meshObject, io, vertex_map)
+
+        mesh.update()
+        return meshObject
+
+    mesh_objects=[__importMeshAndShape(material16, 'with_shape')
+        for material16 in __splitList(material_with_shape, 16)]
+    
+    mesh_objects+=[__importMeshAndShape(material16, 'mesh')
+        for material16 in __splitList(material_without_shape, 16)]
+    return mesh_objects
+
+
+def __importConstraints(io):
+    if isBlender24():
+        return
+    print("create constraint")
+    container=bl.object.createEmpty('Constraints')
+    layer=[
+        True, False, False, False, False, False, False, False, False, False,
+        False, False, False, False, False, False, False, False, False, False,
+            ]
+    material=bl.material.create('constraint')
+    material.diffuse_color=(1, 0, 0)
+    constraintMeshes=[]
+    for i, c in enumerate(io.constraints):
+        bpy.ops.mesh.primitive_uv_sphere_add(
+                segments=8,
+                rings=4,
+                size=0.1,
+                location=(c.pos.x, c.pos.z, c.pos.y),
+                layer=layer
+                )
+        meshObject=bl.object.getActive()
+        constraintMeshes.append(meshObject)
+        mesh=bl.object.getData(meshObject)
+        bl.mesh.addMaterial(mesh, material)
+        meshObject.name='c_%d' % i
+        #meshObject.draw_transparent=True
+        #meshObject.draw_wire=True
+        meshObject.max_draw_type='SOLID'
+        rot=c.rot
+        meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
+
+        meshObject[CONSTRAINT_NAME]=c.getName()
+        meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
+        meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
+        meshObject[CONSTRAINT_POS_MIN]=VtoV(c.constraintPosMin)
+        meshObject[CONSTRAINT_POS_MAX]=VtoV(c.constraintPosMax)
+        meshObject[CONSTRAINT_ROT_MIN]=VtoV(c.constraintRotMin)
+        meshObject[CONSTRAINT_ROT_MAX]=VtoV(c.constraintRotMax)
+        meshObject[CONSTRAINT_SPRING_POS]=VtoV(c.springPos)
+        meshObject[CONSTRAINT_SPRING_ROT]=VtoV(c.springRot)
+
+    for meshObject in reversed(constraintMeshes):
+        bl.object.makeParent(container, meshObject)
+
+    return container
+
+
+def __importRigidBodies(io):
+    if isBlender24():
+        return
+    print("create rigid bodies")
+
+    container=bl.object.createEmpty('RigidBodies')
+    layer=[
+        True, False, False, False, False, False, False, False, False, False,
+        False, False, False, False, False, False, False, False, False, False,
+            ]
+    material=bl.material.create('rigidBody')
+    rigidMeshes=[]
+    for i, rigid in enumerate(io.rigidbodies):
+        if rigid.boneIndex==0xFFFF:
+            # no reference bone
+            bone=io.bones[0]
+        else:
+            bone=io.bones[rigid.boneIndex]
+        pos=bone.pos+rigid.position
+
+        if rigid.shapeType==pmd.SHAPE_SPHERE:
+            bpy.ops.mesh.primitive_ico_sphere_add(
+                    location=(pos.x, pos.z, pos.y),
+                    layer=layer
+                    )
+            bpy.ops.transform.resize(
+                    value=(rigid.w, rigid.w, rigid.w))
+        elif rigid.shapeType==pmd.SHAPE_BOX:
+            bpy.ops.mesh.primitive_cube_add(
+                    location=(pos.x, pos.z, pos.y),
+                    layer=layer
+                    )
+            bpy.ops.transform.resize(
+                    value=(rigid.w, rigid.d, rigid.h))
+        elif rigid.shapeType==pmd.SHAPE_CAPSULE:
+            bpy.ops.mesh.primitive_tube_add(
+                    location=(pos.x, pos.z, pos.y),
+                    layer=layer
+                    )
+            bpy.ops.transform.resize(
+                    value=(rigid.w, rigid.w, rigid.h))
+        else:
+            assert(False)
+
+        meshObject=bl.object.getActive()
+        mesh=bl.object.getData(meshObject)
+        rigidMeshes.append(meshObject)
+        bl.mesh.addMaterial(mesh, material)
+        meshObject.name='r_%d' % i
+        meshObject[RIGID_NAME]=rigid.getName()
+        #meshObject.draw_transparent=True
+        #meshObject.draw_wire=True
+        meshObject.max_draw_type='WIRE'
+        rot=rigid.rotation
+        meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
+
+        # custom properties
+        meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
+        meshObject[RIGID_PROCESS_TYPE]=rigid.processType
+
+        bone_name = englishmap.getEnglishBoneName(bone.getName())
+        if not bone_name:
+            bone_name=bone.getName()
+        meshObject[RIGID_BONE_NAME]=bone_name
+
+        meshObject[RIGID_GROUP]=rigid.group
+        meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
+        meshObject[RIGID_WEIGHT]=rigid.weight
+        meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
+        meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
+        meshObject[RIGID_RESTITUTION]=rigid.restitution
+        meshObject[RIGID_FRICTION]=rigid.friction
+
+    for meshObject in reversed(rigidMeshes):
+        bl.object.makeParent(container, meshObject)
+
+    return container
+
+
+def _execute(filename):
+    """
+    load pmd file to context.
+    """
+           
+    # load pmd
+    bl.progress_set('load %s' % filename, 0.0)
+
+    io=pmd.IO()
+    if not io.read(filename):
+        bl.message("fail to load %s" % filename)
+        return
+    bl.progress_set('loaded', 0.1)
+
+    # create root object
+    model_name=io.getEnglishName()
+    if len(model_name)==0:
+        model_name=io.getName()
+    root=bl.object.createEmpty(model_name)
+    root[MMD_MB_NAME]=io.getName()
+    root[MMD_MB_COMMENT]=io.getComment()
+    root[MMD_COMMENT]=io.getEnglishComment()
+
+    # toon textures
+    tex_dir=os.path.dirname(filename)
+    toonTextures, toonMaterial=__importToonTextures(io, tex_dir)
+    bl.object.makeParent(root, toonTextures)
+
+    # import mesh
+    mesh_objects=__importMaterialAndMesh(io, tex_dir, toonMaterial)
+    for o in mesh_objects:
+        bl.object.makeParent(root, o)
+
+    # import armature
+    armature_object=__importArmature(io)
+    if armature_object:
+        bl.object.makeParent(root, armature_object)
+        armature = bl.object.getData(armature_object) 
+
+        # add armature modifier
+        for o in mesh_objects:
+            bl.modifier.addArmature(o, armature_object)
+
+        # Limitation
+        for n, b in bl.object.getPose(armature_object).bones.items():
+            poseBoneLimit(n, b)
+
+    # import rigid bodies
+    rigidBodies=__importRigidBodies(io)
+    if rigidBodies:
+        bl.object.makeParent(root, rigidBodies)
+
+    # import constraints
+    constraints=__importConstraints(io)
+    if constraints:
+        bl.object.makeParent(root, constraints)
+
+    bl.object.activate(root)
+
+
+if isBlender24():
+    # for 2.4
+    def execute_24(filename):
+        bl.initialize('pmd_import', bpy.data.scenes.active)
+        _execute(filename.decode(bl.INTERNAL_ENCODING))
+        bl.finalize()
+
+    Blender.Window.FileSelector(
+            execute_24, 
+            'Import PMD file', 
+            Blender.sys.makename(ext='.pmd'))
+
+else:
+    # 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.
+        filepath = bpy.props.StringProperty()
+        filename = bpy.props.StringProperty()
+        directory = bpy.props.StringProperty()
+
+        def execute(self, context):
+            bl.initialize('pmd_import', context.scene)
+            _execute(self.properties.filepath)
+            bl.finalize()
+            return 'FINISHED'
+
+        def invoke(self, context, event):
+            wm = context.window_manager
+            try:
+                wm.fileselect_add(self)
+            except:
+                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)",
+                icon='PLUGIN'
+                )
+
+    def register():
+        bpy.types.INFO_MT_file_import.append(menu_func)
+
+    def unregister():
+        bpy.types.INFO_MT_file_import.remove(menu_func)
+
+    if __name__=="__main__":
+        register()
+
diff --git a/pymeshio/pymeshio/__init__.py b/pymeshio/pymeshio/__init__.py
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/pymeshio/pymeshio/englishmap.py b/pymeshio/pymeshio/englishmap.py
new file mode 100755 (executable)
index 0000000..301f3bc
--- /dev/null
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+# coding: utf8
+"""
+日本語名との変換マップ
+"""
+import sys
+
+"""
+ボーン名変換
+"""
+boneMap=[
+("center", "センター", 1),
+("upper body", "上半身"),
+("neck", "首"),
+("head", "頭"),
+("eye_L", "左目", 5),
+("eye_R", "右目", 5),
+("necktie1", "ネクタイ1"),
+("necktie2", "ネクタイ2"),
+("necktie3", "ネクタイ3"),
+("lower body", "下半身"),
+("waist accessory", "腰飾り"),
+("hair1_L", "左髪1"),
+("hair2_L", "左髪2"),
+("hair3_L", "左髪3"),
+("hair4_L", "左髪4"),
+("hair5_L", "左髪5"),
+("hair6_L", "左髪6"),
+("shoulder_L", "左肩"),
+("arm_L", "左腕"),
+("arm twist_L", "左腕捩", 8),
+("elbow_L", "左ひじ"),
+("wrist twist_L", "左手捩", 8),
+("wrist_L", "左手首"),
+("sleeve_L", "左袖", 1),
+("thumb1_L", "左親指1"),
+("thumb2_L", "左親指2"),
+("fore1_L", "左人指1"),
+("fore2_L", "左人指2"),
+("fore3_L", "左人指3"),
+("middle1_L", "左中指1"),
+("middle2_L", "左中指2"),
+("middle3_L", "左中指3"),
+("third1_L", "左薬指1"),
+("third2_L", "左薬指2"),
+("third3_L", "左薬指3"),
+("little1_L", "左小指1"),
+("little2_L", "左小指2"),
+("little3_L", "左小指3"),
+("front skirt_L", "左スカート前"),
+("back skirt_L", "左スカート後"),
+("leg_L", "左足"),
+("knee_L", "左ひざ"),
+("ankle_L", "左足首"),
+("hair1_R", "右髪1"),
+("hair2_R", "右髪2"),
+("hair3_R", "右髪3"),
+("hair4_R", "右髪4"),
+("hair5_R", "右髪5"),
+("hair6_R", "右髪6"),
+("shoulder_R", "右肩"),
+("arm_R", "右腕"),
+("arm twist_R", "右腕捩", 8),
+("elbow_R", "右ひじ"),
+("wrist twist_R", "右手捩", 8),
+("wrist_R", "右手首"),
+("sleeve_R", "右袖", 1),
+("thumb1_R", "右親指1"),
+("thumb2_R", "右親指2"),
+("fore1_R", "右人指1"),
+("fore2_R", "右人指2"),
+("fore3_R", "右人指3"),
+("middle1_R", "右中指1"),
+("middle2_R", "右中指2"),
+("middle3_R", "右中指3"),
+("third1_R", "右薬指1"),
+("third2_R", "右薬指2"),
+("third3_R", "右薬指3"),
+("little1_R", "右小指1"),
+("little2_R", "右小指2"),
+("little3_R", "右小指3"),
+("front skirt_R", "右スカート前"),
+("back skirt_R", "右スカート後"),
+("leg_R", "右足"),
+("knee_R", "右ひざ"),
+("ankle_R", "右足首"),
+("eyes", "両目"),
+("front hair1", "前髪1"),
+("front hair2", "前髪2"),
+("front hair3", "前髪3"),
+("eyelight_L", "左目光"),
+("eyelight_R", "右目光"),
+("necktie3_t", "ネクタイ4"),
+("hair6_L_t", "左髪7"),
+("hair6_R_t", "右髪7"),
+("ankle_L_t", "左つま先"),
+("ankle_R_t", "右つま先"),
+("necktie IK", "ネクタイIK"),
+("hair IK_L", "左髪IK"),
+("hair IK_R", "右髪IK"),
+("leg IK_L", "左足IK"),
+("leg IK_R", "右足IK"),
+("toe IK_L", "左つま先IK"),
+("toe IK_R", "右つま先IK"),
+
+("lower body_t", "下半身先"),
+("head_t", "頭先"),
+("eye_L_t", "左目先"),
+("eye_R_t", "右目先"),
+("waist accessory_t", "腰飾り先"),
+
+("sleeve_L_t", "左袖先"),
+("wrist_L_t", "左手先"),
+("thumb2_L_t", "左親指先"),
+("fore3_L_t", "左人差指先"),
+("middle3_L_t", "左中指先"),
+("third3_L_t", "左薬指先"),
+("little3_L_t", "左小指先"),
+("front skirt_L_t", "左スカート前先"),
+("back skirt_L_t", "左スカート後先"),
+
+("sleeve_R_t", "右袖先"),
+("wrist_R_t", "右手先"),
+("thumb2_R_t", "右親指先"),
+("fore3_R_t", "右人差指先"),
+("middle3_R_t", "右中指先"),
+("third3_R_t", "右薬指先"),
+("little3_R_t", "右小指先"),
+("front skirt_R_t", "右スカート前先"),
+("back skirt_R_t", "右スカート後先"),
+
+("center_t", "センター先"),
+("eyes_t", "両目先"),
+("necktie IK_t", "ネクタイIK先"),
+("hair IK_L_t", "左髪IK先"),
+("hair IK_R_t", "右髪IK先"),
+("leg IK_L_t", "左足IK先"),
+("leg IK_R_t", "右足IK先"),
+("toe IK_L_t", "左つま先IK先"),
+("toe IK_R_t", "右つま先IK先"),
+("front hair1_t", "前髪1先"),
+("front hair2_t", "前髪2先"),
+("front hair3_t", "前髪3先"),
+("eyelight_L_t", "左目光先"),
+("eyelight_R_t", "右目光先"),
+("arm twist_L_t", "左腕捩先"),
+("wrist twist_L_t", "左手捩先"),
+("arm twist_R_t", "右腕捩先"),
+("wrist twist_R_t", "右手捩先"),
+("arm twist1_L", "左腕捩1", 9),
+("arm twist2_L", "左腕捩2", 9),
+("arm twist3_L", "左腕捩3", 9),
+("arm twist1_R", "右腕捩1", 9),
+("arm twist2_R", "右腕捩2", 9),
+("arm twist3_R", "右腕捩3", 9),
+#
+("arm twist1_L_t", "左腕捩1先"),
+("arm twist2_L_t", "左腕捩2先"),
+("arm twist3_L_t", "左腕捩3先"),
+("arm twist1_R_t", "右腕捩1先"),
+("arm twist2_R_t", "右腕捩2先"),
+("arm twist3_R_t", "右腕捩3先"),
+
+# 追加ボーン
+("root", "全ての親"),
+("root_t", "全ての親先"),
+("group", "グループ"),
+("group_t", "グループ先"),
+("front_shirt_L", "左シャツ前"),
+("front_shirt_R", "右シャツ前"),
+("back_shirt_L", "左シャツ後"),
+("back_shirt_R", "右シャツ後"),
+]
+def getEnglishBoneName(name):
+    for v in boneMap:
+        if v[1]==name:
+            return v[0]
+
+def getIndexByEnglish(name):
+    for i, v in enumerate(boneMap):
+        if v[0]==name:
+            return i
+
+def getUnicodeBoneName(name):
+    for v in boneMap:
+        if v[0]==name:
+            return v
+
+"""
+モーフ名変換
+"""
+skinMap=[
+("base", "base", 0),
+("serious", "真面目", 1),
+("sadness", "困る", 1),
+("cheerful", "にこり", 1),
+("anger", "怒り", 1),
+("go up", "上", 1),
+("go down", "下", 1),
+("blink", "まばたき", 2),
+("smile", "笑い", 2),
+("wink", "ウィンク", 2),
+("wink2", "ウィンク2", 2),
+("wink_R", "ウィンク右", 2),
+("wink2_R", "ウィンク2右", 2),
+("close><", "はぅ", 2),
+("calm", "なごみ", 2),
+("surprise", "びっくり", 2),
+("doubt", "じと目", 2),
+("confuse", "なぬ!", 2),
+("pupil", "瞳小", 4),
+("a", "あ", 3),
+("i", "い", 3),
+("u", "う", 3),
+("o", "お", 3),
+("triangle", "▲", 3),
+("regret", "∧", 3),
+("omega", "ω", 3),
+("omegabox", "ω□", 3),
+("fool", "はんっ!", 3),
+("tongue", "ぺろっ", 4),
+("e-", "えー", 3),
+("grin", "にやり", 3),
+]
+def getEnglishSkinName(name):
+    for v in skinMap:
+        if v[1]==name:
+            return v[0]
+
+def getUnicodeSkinName(name):
+    for v in skinMap:
+        if v[0]==name:
+            return v
+
+"""
+ボーングループ名変換
+"""
+boneGroupMap=[
+        ("IK", "IK"),
+        ("Body[u]", "体(上)"),
+        ("Hair", "髪"),
+        ("Arms", "腕"),
+        ("Fingers", "指"),
+        ("Body[l]", "体(下)"),
+        ("Legs", "足"),
+        ]
+def getEnglishBoneGroupName(name):
+    for v in boneGroupMap:
+        if v[1]==name:
+            return v[0]
+
+def getUnicodeBoneGroupName(name):
+    for v in boneGroupMap:
+        if v[0]==name:
+            return v[1]
+
+
+###############################################################################
+# blender2.4 str to unicode
+###############################################################################
+if sys.version_info[0]<3:
+    print('convert boneMap and skinMap to unicode...')
+    # python2.x
+    # unicodeに変換
+    for i, l in enumerate(boneMap):
+        replace=[]
+        for j, m in enumerate(l):
+            if j==1:
+                replace.append(m.decode('utf-8'))
+            else:
+                replace.append(m)
+        boneMap[i]=replace
+
+    for i, l in enumerate(skinMap):
+        replace=[]
+        for j, m in enumerate(l):
+            if j==1:
+                replace.append(m.decode('utf-8'))
+            else:
+                replace.append(m)
+        skinMap[i]=replace
+    print('done')        
+
diff --git a/pymeshio/pymeshio/mmd.py b/pymeshio/pymeshio/mmd.py
new file mode 100755 (executable)
index 0000000..00d9ecf
--- /dev/null
@@ -0,0 +1,1341 @@
+#!/usr/bin/python
+# coding: utf-8
+"""
+20091202: VPD読み込みを追加
+20100318: PMD書き込みを追加
+20100731: meshioと互換になるように改造
+
+VMDの読み込み
+http://yumin3123.at.webry.info/200810/article_4.html
+http://atupdate.web.fc2.com/vmd_format.htm
+
+PMDの読み込み
+http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
+
+VPDの読み込み
+
+ToDo:
+    rigdid bodies
+    constraints
+"""
+import sys
+import codecs
+import os.path
+import struct
+import math
+import re
+#import numpy
+from decimal import *
+
+ENCODING='cp932'
+
+if sys.version_info[0]>=3:
+    xrange=range
+
+###############################################################################
+# utility
+###############################################################################
+def truncate_zero(src):
+    """
+    0x00以降を捨てる
+    """
+    pos = src.find(b"\x00")
+    assert(type(src)==bytes)
+    if pos >= 0:
+        return src[:pos]
+    else:
+        return src
+
+def radian_to_degree(x):
+    return x/math.pi * 180.0
+
+
+###############################################################################
+# geometry
+###############################################################################
+class Vector2(object):
+    __slots__=['x', 'y']
+    def __init__(self, x=0, y=0):
+        self.x=x
+        self.y=y
+
+    def __str__(self):
+        return "<%f %f>" % (self.x, self.y)
+
+    def __getitem__(self, key):
+        if key==0:
+            return self.x
+        elif key==1:
+            return self.y
+        else:
+            assert(False)
+
+    def to_tuple(self):
+        return (self.x, self.y)
+
+
+class Vector3(object):
+    __slots__=['x', 'y', 'z']
+    def __init__(self, x=0, y=0, z=0):
+        self.x=x
+        self.y=y
+        self.z=z
+
+    def __str__(self):
+        return "<%f %f %f>" % (self.x, self.y, self.z)
+
+    def __getitem__(self, key):
+        if key==0:
+            return self.x
+        elif key==1:
+            return self.y
+        elif key==2:
+            return self.z
+        else:
+            assert(False)
+
+    def to_tuple(self):
+        return (self.x, self.y, self.z)
+
+class Quaternion(object):
+    __slots__=['x', 'y', 'z', 'w']
+    def __init__(self, x=0, y=0, z=0, w=1):
+        self.x=x
+        self.y=y
+        self.z=z
+        self.w=w
+
+    def __str__(self):
+        return "<%f %f %f %f>" % (self.x, self.y, self.z, self.w)
+
+    def __mul__(self, rhs):
+        u=numpy.array([self.x, self.y, self.z], 'f')
+        v=numpy.array([rhs.x, rhs.y, rhs.z], 'f')
+        xyz=self.w*v+rhs.w*u+numpy.cross(u, v)
+        q=Quaternion(xyz[0], xyz[1], xyz[2], self.w*rhs.w-numpy.dot(u, v))
+        return q
+
+    def dot(self, rhs):
+        return self.x*rhs.x+self.y*rhs.y+self.z*rhs.z+self.w*rhs.w
+
+    def getMatrix(self):
+        sqX=self.x*self.x
+        sqY=self.y*self.y
+        sqZ=self.z*self.z
+        xy=self.x*self.y
+        xz=self.x*self.z
+        yz=self.y*self.z
+        wx=self.w*self.x
+        wy=self.w*self.y
+        wz=self.w*self.z
+        return numpy.array([
+                # 1
+                [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
+                # 2
+                [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
+                # 3
+                [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
+                # 4
+                [0, 0, 0, 1]],
+                'f')
+
+    def getRHMatrix(self):
+        x=-self.x
+        y=-self.y
+        z=self.z
+        w=self.w
+        sqX=x*x
+        sqY=y*y
+        sqZ=z*z
+        xy=x*y
+        xz=x*z
+        yz=y*z
+        wx=w*x
+        wy=w*y
+        wz=w*z
+        return numpy.array([
+                # 1
+                [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
+                # 2
+                [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
+                # 3
+                [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
+                # 4
+                [0, 0, 0, 1]],
+                'f')
+
+    def getRollPitchYaw(self):
+        m=self.getMatrix()
+
+        roll = math.atan2(m[0, 1], m[1, 1])
+        pitch = math.asin(-m[2, 1])
+        yaw = math.atan2(m[2, 0], m[2, 2])
+
+        if math.fabs(math.cos(pitch)) < 1.0e-6:
+            roll += m[0, 1] > math.pi if 0.0 else -math.pi
+            yaw += m[2, 0] > math.pi if 0.0 else -math.pi
+
+        return roll, pitch, yaw
+
+    def getSqNorm(self):
+        return self.x*self.x+self.y*self.y+self.z*self.z+self.w*self.w
+
+    def getNormalized(self):
+        f=1.0/self.getSqNorm()
+        q=Quaternion(self.x*f, self.y*f, self.z*f, self.w*f)
+        return q
+
+    def getRightHanded(self):
+        "swap y and z axis"
+        return Quaternion(-self.x, -self.z, -self.y, self.w)
+
+    @staticmethod
+    def createFromAxisAngle(axis, rad):
+        q=Quaternion()
+        half_rad=rad/2.0
+        c=math.cos(half_rad)
+        s=math.sin(half_rad)
+        return Quaternion(axis[0]*s, axis[1]*s, axis[2]*s, c)
+
+
+class RGBA(object):
+    __slots__=['r', 'g', 'b', 'a']
+    def __init__(self, r=0, g=0, b=0, a=1):
+        self.r=r
+        self.g=g
+        self.b=b
+        self.a=a
+
+    def __getitem__(self, key):
+        if key==0:
+            return self.r
+        elif key==1:
+            return self.g
+        elif key==2:
+            return self.b
+        elif key==3:
+            return self.a
+        else:
+            assert(False)
+
+
+###############################################################################
+# VMD
+###############################################################################
+class ShapeData(object):
+    __slots__=['name', 'frame', 'ratio']
+    def __init__(self, name):
+        self.name=name
+        self.frame=-1
+        self.ratio=0
+
+    def __cmp__(self, other):
+        return cmp(self.frame, other.frame)
+
+class MotionData(object):
+    __slots__=['name', 'frame', 'pos', 'q', 'complement']
+    def __init__(self, name):
+        self.name=name
+        self.frame=-1
+        self.pos=Vector3()
+        self.q=Quaternion()
+
+    def __cmp__(self, other):
+        return cmp(self.frame, other.frame)
+
+    def __str__(self):
+        return '<MotionData "%s" %d %s%s>' % (self.name, self.frame, self.pos, self.q)
+
+class VMDLoader(object):
+    __slots__=['io', 'end', 'signature',
+            'model_name', 'last_frame',
+            'motions', 'shapes', 'cameras', 'lights',
+            ]
+    def __init__(self):
+        self.model_name=''
+        self.motions=[]
+        self.shapes=[]
+        self.cameras=[]
+        self.lights=[]
+        self.last_frame=0
+
+    def __str__(self):
+        return '<VMDLoader model: "%s", motion: %d, shape: %d, camera: %d, light: %d>' % (
+            self.model_name, len(self.motions), len(self.shapes),
+            len(self.cameras), len(self.lights))
+
+    def load(self, path, io, end):
+        self.io=io
+        self.end=end
+
+        # signature
+        self.signature=truncate_zero(self.io.read(30))
+        version=self.validate_signature(self.signature)
+        if not version:
+            print("invalid signature", self.signature)
+            return False
+
+        if version==1:
+            if not self.load_verstion_1():
+                return False
+        elif version==2:
+            if not  self.load_verstion_2():
+                return False 
+        else:
+            raise Exception("unknown version") 
+
+        # post process
+        motions=self.motions
+        self.motions={}
+        for m in motions:
+            if not m.name in self.motions:
+                self.motions[m.name]=[]
+            self.motions[m.name].append(m)
+        for name in self.motions.keys():
+            self.motions[name].sort()
+
+        shapes=self.shapes
+        self.shapes={}
+        for s in shapes:
+            if not s.name in self.shapes:
+                self.shapes[s.name]=[]
+            self.shapes[s.name].append(s)
+        for name in self.shapes.keys():
+            self.shapes[name].sort()
+
+        return True
+
+    def getMotionCount(self):
+        count=0
+        for v in self.motions.values():
+            count+=len(v)
+        return count
+
+    def getShapeCount(self):
+        count=0
+        for v in self.shapes.values():
+            count+=len(v)
+        return count
+
+    def load_verstion_1(self):
+        # model name
+        self.model_name=truncate_zero(self.io.read(10))
+        if not self.loadMotion_1():
+            return False
+        return True
+
+    def loadMotion_1(self):
+        count=struct.unpack('H', self.io.read(2))[0]
+        self.io.read(2)
+        for i in xrange(0, count):
+            self.loadFrameData()
+        return True
+
+    ############################################################
+    def load_verstion_2(self):
+        # model name
+        self.model_name=truncate_zero(self.io.read(20))
+
+        if not self.loadMotion():
+            return False
+        if not self.loadShape():
+            return False
+        if not self.loadCamera():
+            return False
+        if not self.loadLight():
+            return False
+        #assert(self.io.tell()==self.end)
+        #self.motions.sort(lambda l, r: l.name<r.name)
+
+        return True
+
+    def validate_signature(self, signature):
+        if self.signature == "Vocaloid Motion Data 0002":
+            return 2
+        if self.signature == "Vocaloid Motion Data file":
+            return 1
+        else:
+            return None
+
+    def loadMotion(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            self.loadFrameData()
+        return True
+
+    def loadShape(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            self.loadShapeData()
+        return True
+
+    def loadCamera(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            # not implemented
+            assert(False)
+            pass
+        return True
+
+    def loadLight(self):
+        count=struct.unpack('I', self.io.read(4))[0]
+        for i in xrange(0, count):
+            # not implemented
+            assert(False)
+            pass
+        return True
+
+    def loadFrameData(self):
+        """
+        フレームひとつ分を読み込む
+        """
+        data=MotionData(truncate_zero(self.io.read(15)))
+        (data.frame, data.pos.x, data.pos.y, data.pos.z,
+        data.q.x, data.q.y, data.q.z, data.q.w) = struct.unpack(
+                'I7f', self.io.read(32))
+        # complement data
+        data.complement=''.join(
+                ['%x' % x for x in struct.unpack('64B', self.io.read(64))])
+        self.motions.append(data)
+        if data.frame>self.last_frame:
+            self.last_frame=data.frame
+
+    def loadShapeData(self):
+        """
+        モーフデータひとつ分を読み込む
+        """
+        data=ShapeData(truncate_zero(self.io.read(15)))
+        (data.frame, data.ratio)=struct.unpack('If', self.io.read(8))
+        self.shapes.append(data)
+        if data.frame>self.last_frame:
+            self.last_frame=data.frame
+
+    # vmd -> csv
+    ############################################################
+    def create_csv_line(m):
+        # quaternion -> euler angle
+        (roll, pitch, yaw)=m.q.getRollPitchYaw()
+        return '%s,%d,%g,%g,%g,%g,%g,%g,0x%s\n' % (
+                m.name, m.frame, m.pos.x, m.pos.y, m.pos.z,
+                to_degree(pitch), to_degree(yaw), to_degree(roll), m.complement
+                )
+
+    def write_csv(l, path):
+        sys.setdefaultencoding('cp932')
+        csv=open(path, "w")
+        csv.write('%s,0\n' % l.signature)
+        csv.write('%s\n' % l.model_name)
+        # motion
+        csv.write('%d\n' % len(l.motions))
+        for m in l.motions:
+            csv.write(create_csv_line(m))
+        # shape
+        csv.write('%d\n' % len(l.shapes))
+        for s in l.shapes:
+            csv.write('%s,%d,%f\n' % ( s.name, s.frame, s.ratio))
+        # camera
+        csv.write('%d\n' % len(l.cameras))
+        for camera in l.cameras:
+            assert(False)
+        # light
+        csv.write('%d\n' % len(l.lights))
+        for light in l.lights:
+            assert(False)
+
+
+###############################################################################
+# PMD
+###############################################################################
+class Vertex(object):
+    __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
+    def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
+            bone0=0, bone1=0, weight0=0, edge_flag=0):
+        self.pos=Vector3(x, y, z)
+        self.normal=Vector3(nx, ny, nz)
+        self.uv=Vector2(u, v)
+        self.bone0=bone0
+        self.bone1=bone1
+        self.weight0=weight0
+        self.edge_flag=edge_flag
+
+    def __str__(self):
+        return "<%s %s %s, (%d, %d, %d)>" % (str(self.pos), str(self.normal), str(self.uv), self.bone0, self.bone1, self.weight0)
+
+    def __getitem__(self, key):
+        if key==0:
+            return self.pos.x
+        elif key==1:
+            return self.pos.y
+        elif key==2:
+            return self.pos.z
+        else:
+            assert(False)
+
+class Material(object):
+    __slots__=[
+            'diffuse', 'shinness', 'specular',
+            'ambient', 'vertex_count', 'texture', 'toon_index', 'flag',
+            ]
+
+    def __init__(self, dr=0, dg=0, db=0, alpha=1, 
+            specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
+        self.diffuse=RGBA(dr, dg, db, alpha)
+        self.specular=RGBA(sr, sg, sb)
+        self.shinness=specular
+        self.ambient=RGBA(ar, ag, ab)
+        self.vertex_count=0
+        self.texture=''
+        self.toon_index=0
+        self.flag=0
+
+    def __str__(self):
+        return "<Material [%f, %f, %f, %f]>" % (
+                self.diffuse[0], self.diffuse[1], 
+                self.diffuse[2], self.diffuse[3],
+                )
+
+    def getTexture(self): return self.texture.decode('cp932')
+    def setTexture(self, u): self.texture=u
+
+# @return 各マテリアルについて、そのマテリアルが保持する面の回数だけ
+# マテリアル自身を返す
+def material_per_face(materials):
+    for m in materials:
+        for x in xrange(int(m.vertex_count/3)):
+            yield m
+
+class Bone(object):
+    # kinds
+    ROTATE = 0
+    ROTATE_MOVE = 1
+    IK = 2
+    IK_ROTATE_INFL = 4
+    ROTATE_INFL = 5
+    IK_TARGET = 6
+    UNVISIBLE = 7
+    # since v4.0
+    ROLLING=8 # ?
+    TWEAK=9
+    __slots__=['name', 'index', 'type', 'parent', 'ik', 'pos',
+            'children', 'english_name', 'ik_index',
+            'parent_index', 'tail_index', 'tail',
+            ]
+    def __init__(self, name='bone', type=0):
+        self.name=name
+        self.index=0
+        self.type=type
+        self.parent_index=0xFFFF
+        self.tail_index=0
+        self.tail=Vector3(0, 0, 0)
+        self.parent=None
+        self.ik_index=0xFFFF
+        self.pos=Vector3(0, 0, 0)
+        self.children=[]
+        self.english_name=''
+
+    def getName(self): return self.name.decode('cp932')
+    def setName(self, u): self.name=u
+    def setEnglishName(self, u): self.english_name=u
+
+    def hasParent(self):
+        return self.parent_index!=0xFFFF
+
+    def hasChild(self):
+        return self.tail_index!=0
+
+    def display(self, indent=[]):
+        if len(indent)>0:
+            prefix=''
+            for i, is_end in enumerate(indent):
+                if i==len(indent)-1:
+                    break
+                else:
+                    prefix+='  ' if is_end else ' |'
+            uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
+            print(uni.encode(ENCODING))
+        else:
+            uni='%s(%s)' % (unicode(self), self.english_name)
+            print(uni.encode(ENCODING))
+
+        child_count=len(self.children)
+        for i in xrange(child_count):
+            child=self.children[i]
+            if i<child_count-1:
+                child.display(indent+[False])
+            else:
+                # last
+                child.display(indent+[True])
+
+# 0
+class Bone_Rotate(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_Rotate, self).__init__(name, 0)
+    def __str__(self):
+        return '<ROTATE %s>' % (self.name)
+# 1
+class Bone_RotateMove(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_RotateMove, self).__init__(name, 1)
+    def __str__(self):
+        return '<ROTATE_MOVE %s>' % (self.name)
+# 2
+class Bone_IK(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_IK, self).__init__(name, 2)
+    def __str__(self):
+        return '<IK %s>' % (self.name)
+# 4
+class Bone_IKRotateInfl(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_IKRotateInfl, self).__init__(name, 4)
+    def __str__(self):
+        return '<IK_ROTATE_INFL %s>' % (self.name)
+# 5
+class Bone_RotateInfl(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_RotateInfl, self).__init__(name, 5)
+    def __str__(self):
+        return '<ROTATE_INFL %s>' % (self.name)
+# 6
+class Bone_IKTarget(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_IKTarget, self).__init__(name, 6)
+    def __str__(self):
+        return '<IK_TARGET %s>' % (self.name)
+# 7
+class Bone_Unvisible(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_Unvisible, self).__init__(name, 7)
+    def __str__(self):
+        return '<UNVISIBLE %s>' % (self.name)
+# 8
+class Bone_Rolling(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_Rolling, self).__init__(name, 8)
+    def __str__(self):
+        return '<ROLLING %s>' % (self.name)
+# 9
+class Bone_Tweak(Bone):
+    __slots__=[]
+    def __init__(self, name):
+        super(Bone_Tweak, self).__init__(name, 9)
+    def __str__(self):
+        return '<TWEAK %s>' % (self.name)
+
+
+def createBone(name, type):
+    if type==0:
+        return Bone_Rotate(name)
+    elif type==1:
+        return Bone_RotateMove(name)
+    elif type==2:
+        return Bone_IK(name)
+    elif type==3:
+        raise Exception("no used bone type: 3(%s)" % name)
+    elif type==4:
+        return Bone_IKRotateInfl(name)
+    elif type==5:
+        return Bone_RotateInfl(name)
+    elif type==6:
+        return Bone_IKTarget(name)
+    elif type==7:
+        return Bone_Unvisible(name)
+    elif type==8:
+        return Bone_Rolling(name)
+    elif type==9:
+        return Bone_Tweak(name)
+    else:
+        raise Exception("unknown bone type: %d(%s)", type, name)
+
+
+class IK(object):
+    __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
+    def __init__(self, index=0, target=0):
+        self.index=index
+        self.target=target
+        self.iterations=None
+        self.weight=None
+        self.children=[]
+
+    def __str__(self):
+        return "<IK index: %d, target: %d, iterations: %d, weight: %f, children: %s(%d)>" %(self.index, self.target, self.iterations, self.weight, '-'.join([str(i) for i in self.children]), len(self.children))
+
+class Skin(object):
+    __slots__=['name', 'type', 'indices', 'pos_list', 'english_name',
+            'vertex_count']
+    def __init__(self, name='skin'):
+        self.name=name
+        self.type=None
+        self.indices=[]
+        self.pos_list=[]
+        self.english_name=''
+        self.vertex_count=0
+
+    def getName(self): return self.name.decode('cp932')
+    def setName(self, u): self.name=u
+    def setEnglishName(self, u): self.english_name=u
+
+    def append(self, index, x, y, z):
+        self.indices.append(index)
+        self.pos_list.append(Vector3(x, y, z))
+
+    def __str__(self):
+        return '<Skin name: "%s", type: %d, vertex: %d>' % (
+            self.name, self.type, len(self.indices))
+
+class ToonTexture(object):
+    __slots__=['name']
+    def __init__(self, name): self.name=name
+    def getName(self): return self.name.decode('cp932')
+    def setName(self, u): self.name=u
+
+class BoneGroup(object):
+    __slots__=['name', 'english_name']
+    def __init__(self, name='group'): self.name=name; self.english_name='center'
+    def getName(self): return self.name.decode('cp932')
+    def setName(self, u): self.name=u
+    def getEnglishName(self): return self.english_name.decode('cp932')
+    def setEnglishName(self, u): self.english_name=u
+
+class PMDLoader(object):
+    __slots__=['io', 'end', 'pos',
+            'version', 'model_name', 'comment',
+            'english_model_name', 'english_comment',
+            'vertices', 'indices', 'materials', 'bones', 
+            'ik_list', 'morph_list',
+            'face_list', 'bone_group_list', 'bone_display_list',
+            'toon_textures',
+            'no_parent_bones',
+            'rigidbodies', 'constraints',
+            ]
+    def __init__(self):
+        self.version=1.0
+        self.model_name=b"default"
+        self.comment=b"default"
+        self.english_model_name=b'default'
+        self.english_comment=b'default'
+        self.vertices=[]
+        self.indices=[]
+        self.materials=[]
+        self.bones=[]
+        self.ik_list=[]
+        self.morph_list=[]
+
+        self.face_list=[]
+        self.bone_group_list=[]
+        self.bone_display_list=[]
+
+        self.toon_textures=[
+                ToonTexture(b'toon'), ToonTexture(b'toon'),
+                ToonTexture(b'toon'), ToonTexture(b'toon'),
+                ToonTexture(b'toon'), ToonTexture(b'toon'),
+                ToonTexture(b'toon'), ToonTexture(b'toon'),
+                ToonTexture(b'toon'), ToonTexture(b'toon'),
+                ]
+
+        self.no_parent_bones=[]
+
+        self.rigidbodies=[]
+        self.constraints=[]
+
+    def getName(self): return self.model_name.decode('cp932')
+    def setName(self, u): self.model_name=u
+    def getComment(self): return self.comment.decode('cp932')
+    def setComment(self, u): self.comment=u
+    def getEnglishName(self): return self.english_model_name.decode('cp932')
+    def setEnglishName(self, u): self.english_model_name=u
+    def getEnglishComment(self): return self.english_comment.decode('cp932')
+    def setEnglishComment(self, u): self.english_comment=u
+
+    def getToonTexture(self, i): return self.toon_textures[i]
+    def each_vertex(self): return self.vertices
+    def getUV(self, i): return self.vertices[i].uv
+    def addVertex(self): 
+        v=Vertex()
+        self.vertices.append(v)
+        return v
+    def addMaterial(self):
+        m=Material()
+        self.materials.append(m)
+        return m
+    def addBone(self):
+        b=Bone()
+        self.bones.append(b)
+        return b
+    def addIK(self):
+        ik=IK()
+        self.ik_list.append(ik)
+        return ik
+    def addMorph(self):
+        s=Skin()
+        self.morph_list.append(s)
+        return s
+    def addBoneGroup(self):
+        g=BoneGroup()
+        self.bone_group_list.append(g)
+        return g
+    def addBoneDisplay(self, b, g):
+        self.bone_display_list.append((b, g))
+
+    def __str__(self):
+        return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
+            self.version, self.model_name, len(self.vertices), len(self.indices),
+            len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
+
+    def _check_position(self):
+        """
+        if self.pos:
+            print(self.pos, self.io.tell()-self.pos)
+        """
+        self.pos=self.io.tell()
+        pass
+
+    def read(self, path):
+        size=os.path.getsize(path)
+        f=open(path, "rb")
+        return self.load(path, f, size)
+
+    def load(self, path, io, end):
+        self.io=io
+        self.pos=self.io.tell()
+        self.end=end
+        self._check_position()
+
+        if not self._loadHeader():
+            return False
+        self._check_position()
+
+        if not self._loadVertex():
+            return False
+        self._check_position()
+
+        if not self._loadFace():
+            return False
+        self._check_position()
+
+        if not self._loadMaterial():
+            return False
+        self._check_position()
+
+        if not self._loadBone():
+            return False
+        self._check_position()
+
+        if not self._loadIK():
+            return False
+        self._check_position()
+
+        if not self._loadSkin():
+            return False
+        self._check_position()
+
+        if not self._loadSkinIndex():
+            return False
+        self._check_position()
+
+        if not self._loadBoneName():
+            return False
+        self._check_position()
+
+        if not self._loadBoneIndex():
+            return False
+        self._check_position()
+
+        if not self._loadExtend():
+            print('fail to loadExtend')
+            return False
+
+        # 終端
+        if self.io.tell()!=self.end:
+            print("can not reach eof.")
+            print("current: %d, end: %d, remain: %d" % (
+                    self.io.tell(), self.end, self.end-self.io.tell()))
+
+        # build bone tree
+        for i, child in enumerate(self.bones):
+            if child.parent_index==0xFFFF:
+                # no parent
+                self.no_parent_bones.append(child)
+                child.parent=None
+            else:
+                # has parent
+                parent=self.bones[child.parent_index]
+                child.parent=parent
+                parent.children.append(child)
+            # 後位置
+            if child.hasChild():
+                child.tail=self.bones[child.tail_index].pos
+
+        return True
+
+    def write(self, path):
+        io=open(path, 'wb')
+        if not io:
+            return False
+        # Header
+        io.write(b"Pmd")        
+        io.write(struct.pack("f", self.version))
+        io.write(struct.pack("20s", self.model_name))
+        io.write(struct.pack("256s", self.comment))
+
+        # Vertices
+        io.write(struct.pack("I", len(self.vertices)))
+        sVertex=struct.Struct("=8f2H2B") # 38byte
+        assert(sVertex.size==38)
+        for v in self.vertices:
+            data=sVertex.pack( 
+                v.pos[0], v.pos[1], v.pos[2],
+                v.normal[0], v.normal[1], v.normal[2],
+                v.uv[0], v.uv[1],
+                v.bone0, v.bone1, v.weight0, v.edge_flag)
+            io.write(data)
+
+        # Faces
+        io.write(struct.pack("I", len(self.indices)))
+        io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
+
+        # material
+        io.write(struct.pack("I", len(self.materials)))
+        sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
+        assert(sMaterial.size==70)
+        for m in self.materials:
+            io.write(sMaterial.pack(
+                m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
+                m.shinness, 
+                m.specular[0], m.specular[1], m.specular[2],
+                m.ambient[0], m.ambient[1], m.ambient[2],
+                m.toon_index, m.flag,
+                m.vertex_count,
+                m.texture
+                ))
+
+        # bone
+        io.write(struct.pack("H", len(self.bones)))
+        sBone=struct.Struct("=20sHHBH3f")
+        assert(sBone.size==39)
+        for b in self.bones:
+            io.write(sBone.pack(
+                b.name,
+                b.parent_index, b.tail_index, b.type, b.ik_index,
+                b.pos[0], b.pos[1], b.pos[2]))
+
+        # IK
+        io.write(struct.pack("H", len(self.ik_list)))
+        for ik in self.ik_list:
+            io.write(struct.pack("=2HBHf", 
+                ik.index, ik.target, ik.length, ik.iterations, ik.weight
+                ))
+            for c in ik.children:
+                io.write(struct.pack("H", c))
+
+        # skin
+        io.write(struct.pack("H", len(self.morph_list)))
+        for s in self.morph_list:
+            io.write(struct.pack("20sIB", 
+                s.name, len(s.indices), s.type))
+            for i, v in zip(s.indices, s.pos_list):
+                io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
+
+        # skin list
+        io.write(struct.pack("B", len(self.face_list)))
+        for i in self.face_list:
+            io.write(struct.pack("H", i))
+
+        # bone name
+        io.write(struct.pack("B", len(self.bone_group_list)))
+        for g in self.bone_group_list:
+            io.write(struct.pack("50s", g.name))
+
+        # bone list
+        io.write(struct.pack("I", len(self.bone_display_list)))
+        for l in self.bone_display_list:
+            io.write(struct.pack("=HB", *l))
+
+        # ToDo
+        # Extend Data
+
+        return True
+
+
+    def _loadExtend(self):
+        ############################################################
+        # extend1: english name
+        ############################################################
+        if self.io.tell()>=self.end:
+            return True
+        if struct.unpack("B", self.io.read(1))[0]==1:
+            if not self.loadEnglishName():
+                return False
+        self._check_position()
+
+        ############################################################
+        # extend2: toon texture list
+        ############################################################
+        if self.io.tell()>=self.end:
+            return True
+        if not self.loadToonTexture():
+            return False
+        self._check_position()
+
+        ############################################################
+        # extend3: physics
+        ############################################################
+        if self.io.tell()>=self.end:
+            return True
+        #if not self.loadPhysics():
+        #    return False
+        self._check_position()
+
+        return True
+
+    def _loadHeader(self):
+        signature=struct.unpack("3s", self.io.read(3))[0]
+        print(signature)
+        if signature!=b"Pmd":
+            print("invalid signature", signature)
+            return False
+        self.version=struct.unpack("f", self.io.read(4))[0]
+        self.model_name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
+        self.comment = truncate_zero(
+                struct.unpack("256s", self.io.read(256))[0])
+        return True
+
+    def _loadVertex(self):
+        count = struct.unpack("I", self.io.read(4))[0]
+        for i in xrange(count):
+            self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
+        return True
+
+    def _loadFace(self):
+        count = struct.unpack("I", self.io.read(4))[0]
+        for i in xrange(0, count, 3):
+            self.indices+=struct.unpack("HHH", self.io.read(6))
+        return True
+
+    def _loadMaterial(self):
+        count = struct.unpack("I", self.io.read(4))[0]
+        for i in xrange(count):
+            material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
+            material.toon_index=struct.unpack("B", self.io.read(1))[0]
+            material.flag=struct.unpack("B", self.io.read(1))[0]
+            material.vertex_count=struct.unpack("I", self.io.read(4))[0]
+            texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
+            # todo sphere map
+            #material.texture=texture.split('*')[0]
+            material.texture=texture
+            self.materials.append(material)
+        return True
+
+    def _loadBone(self):
+        size = struct.unpack("H", self.io.read(2))[0]
+        for i in xrange(size):
+            name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
+            parent_index, tail_index = struct.unpack("HH", self.io.read(4))
+            type = struct.unpack("B", self.io.read(1))[0]
+            bone=createBone(name, type)
+            bone.parent_index=parent_index
+            bone.tail_index=tail_index
+            bone.ik_index = struct.unpack("H", self.io.read(2))[0]
+            bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
+            bone.english_name="bone%03d" % len(self.bones)
+            self.bones.append(bone)
+        return True
+
+    def _loadIK(self):
+        size = struct.unpack("H", self.io.read(2))[0]
+        for i in xrange(size):
+            ik=IK(*struct.unpack("2H", self.io.read(4)))
+            ik.length = struct.unpack("B", self.io.read(1))[0]
+            ik.iterations = struct.unpack("H", self.io.read(2))[0]
+            ik.weight = struct.unpack("f", self.io.read(4))[0]
+            for j in xrange(ik.length):
+                ik.children.append(struct.unpack("H", self.io.read(2))[0])
+            self.ik_list.append(ik)
+        return True
+
+    def _loadSkin(self):
+        size = struct.unpack("H", self.io.read(2))[0]
+        for i in xrange(size):
+            skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
+            skin_size = struct.unpack("I", self.io.read(4))[0]
+            skin.type = struct.unpack("B", self.io.read(1))[0]
+            for j in xrange(skin_size):
+                skin.indices.append(struct.unpack("I", self.io.read(4))[0])
+                skin.pos_list.append(
+                        Vector3(*struct.unpack("3f", self.io.read(12))))
+            skin.english_name="skin%03d" % len(self.morph_list)
+            self.morph_list.append(skin)
+        return True
+
+    def _loadSkinIndex(self):
+        size = struct.unpack("B", self.io.read(1))[0]
+        for i in xrange(size):
+            self.face_list.append(struct.unpack("H", self.io.read(2))[0])
+        return True
+
+    def _loadBoneName(self):
+        size = struct.unpack("B", self.io.read(1))[0]
+        for i in xrange(size):
+            self.bone_group_list.append(BoneGroup(
+                truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
+        return True
+
+    def _loadBoneIndex(self):
+        size = struct.unpack("I", self.io.read(4))[0]
+        for i in xrange(size):
+            self.bone_display_list.append(struct.unpack("HB", self.io.read(3)))
+        return True
+
+    def loadToonTexture(self):
+        """
+        100bytex10
+        """
+        for i in xrange(10):
+            self.toon_textures.append(ToonTexture(
+                    truncate_zero(struct.unpack("100s", self.io.read(100))[0])))
+        return True
+
+    def loadEnglishName(self):
+        # english name
+        self.english_model_name=truncate_zero(
+                struct.unpack("20s", self.io.read(20))[0])
+        self.english_comment=truncate_zero(
+                struct.unpack("256s", self.io.read(256))[0])
+        # english bone list
+        for bone in self.bones:
+            english_name=truncate_zero(
+                    struct.unpack("20s", self.io.read(20))[0])
+            if english_name!=bone.name:
+                bone.english_name=english_name
+        # english skin list
+        #for index in self.face_list:
+        for skin in self.morph_list:
+            if skin.name=='base':
+                continue
+            english_name=truncate_zero(
+                    struct.unpack("20s", self.io.read(20))[0])
+            #skin=self.morph_list[index]
+            if english_name!=skin.name:
+                skin.english_name=english_name
+        # english bone list
+        for i in xrange(0, len(self.bone_group_list)):
+            self.bone_group_list[i].english_name=truncate_zero(
+                    struct.unpack("50s", self.io.read(50))[0])
+        return True
+
+    def loadPhysics(self):
+        # 剛体リスト
+        count = struct.unpack("I", self.io.read(4))[0]
+        for i in xrange(count):
+            struct.unpack("83s", self.io.read(83))[0]
+        # ジョイントリスト
+        count = struct.unpack("I", self.io.read(4))[0]
+        for i in xrange(count):
+            struct.unpack("124s", self.io.read(124))[0]
+        return True
+
+
+###############################################################################
+# VPD
+###############################################################################
+class LineLoader(object):
+    """
+    行指向の汎用ローダ
+    """
+    __slots__=['path', 'io', 'end']
+    def __str__(self):
+        return "<%s current:%d, end:%d>" % (
+                self.__class__, self.getPos(), self.getEnd())
+
+    def getPos(self):
+        return self.io.tell()
+
+    def getEnd(self):
+        return self.end
+
+    def readline(self):
+        return (self.io.readline()).strip()
+
+    def isEnd(self):
+        return self.io.tell()>=self.end
+
+    def load(self, path, io, end):
+        self.path=path
+        self.io=io
+        self.end=end
+        return self.process()
+
+    def process(self):
+        """
+        dummy. read to end.
+        """
+        while not self.isEnd():
+            self.io.readline()
+        return True
+
+
+class VPDLoader(LineLoader):
+    __slots__=['pose']
+    def __init__(self):
+        super(VPDLoader, self).__init__()
+        self.pose=[]
+
+    def __str__(self):
+        return "<VPD poses:%d>" % len(self.pose)
+
+    def process(self):
+        if self.readline()!="Vocaloid Pose Data file":
+            return
+
+        RE_OPEN=re.compile('^(\w+){(.*)')
+        RE_OSM=re.compile('^\w+\.osm;')
+        RE_COUNT=re.compile('^(\d+);')
+
+        bone_count=-1
+        while not self.isEnd():
+            line=self.readline()
+            if line=='':
+                continue
+            m=RE_OPEN.match(line)
+            if m:
+                if not self.parseBone(m.group(2)):
+                    raise Exception("invalid bone")
+                continue
+
+            m=RE_OSM.match(line)
+            if m:
+                continue
+
+            m=RE_COUNT.match(line)
+            if m:
+                bone_count=int(m.group(1))
+                continue
+
+        return len(self.pose)==bone_count
+
+    def parseBone(self, name):
+        bone=MotionData(name)
+        self.pose.append(bone)
+        bone.pos=Vector3(*[float(token) for token in self.readline().split(';')[0].split(',')])
+        bone.q=Quaternion(*[float(token) for token in self.readline().split(';')[0].split(',')])
+        return self.readline()=="}"
+
+
+###############################################################################
+# interface
+###############################################################################
+def load_pmd(path):
+    size=os.path.getsize(path)
+    f=open(path, "rb")
+    l=PMDLoader()
+    if l.load(path, f, size):
+        return l
+
+def load_vmd(path):
+    size=os.path.getsize(path)
+    f=open(path, "rb")
+    l=VMDLoader()
+    if l.load(path, f, size):
+        return l
+
+def load_vpd(path):
+    f=open(path, 'rb')
+    if not f:
+        return;
+    size=os.path.getsize(path)
+    l=VPDLoader()
+    if l.load(path, f, size):
+        return l
+
+
+###############################################################################
+# debug
+###############################################################################
+def debug_pmd(path):
+    l=load_pmd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+
+    print(unicode(l).encode(ENCODING))
+    print(l.comment.encode(ENCODING))
+    print("<ボーン>".decode('utf-8').encode(ENCODING))
+    for bone in l.no_parent_bones:
+        print(bone.name.encode(ENCODING))
+        bone.display()
+    #for bone in l.bones:
+    #    uni="%s:%s" % (bone.english_name, bone.name)
+    #    print uni.encode(ENCODING)
+    #for skin in l.morph_list:
+    #    uni="%s:%s" % (skin.english_name, skin.name)
+    #    print uni.encode(ENCODING)
+    #for i, v in enumerate(l.vertices):
+    #    print i, v
+    #for i, f in enumerate(l.indices):
+    #    print i, f
+    for m in l.materials:
+        print(m)
+
+def debug_pmd_write(path, out):
+    l=load_pmd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+
+    if not l.write(out):
+        print("fail to write")
+        sys.exit()
+
+def debug_vmd(path):
+    l=load_vmd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+    print(unicode(l).encode(ENCODING))
+
+    #for m in l.motions[u'センター']:
+    #    print m.frame, m.pos
+    for n, m in l.shapes.items():
+        print(unicode(n).encode(ENCODING), getEnglishSkinName(n))
+
+def debug_vpd(path):
+    l=load_vpd(path)
+    if not l:
+        print("fail to load")
+        sys.exit()
+    for bone in l.pose:
+        print(unicode(bone).encode(ENCODING))
+
+if __name__=="__main__":
+    if len(sys.argv)<2:
+        print("usage: %s {pmd file}" % sys.argv[0])
+        print("usage: %s {vmd file}" % sys.argv[0])
+        print("usage: %s {vpd file}" % sys.argv[0])
+        print("usage: %s {pmd file} {export pmdfile}" % sys.argv[0])
+        sys.exit()
+
+    path=sys.argv[1]
+    if not os.path.exists(path):
+        print("no such file: %s" % path)
+
+    if path.lower().endswith('.pmd'):
+        if len(sys.argv)==2:
+            debug_pmd(path)
+        else:
+            debug_pmd_write(path, sys.argv[2])
+    elif path.lower().endswith('.vmd'):
+        debug_vmd(path)
+    elif path.lower().endswith('.vpd'):
+        debug_vpd(path)
+    else:
+        print("unknown file type: %s" % path)
+        sys.exit()
+
diff --git a/pymeshio/pymeshio/mqo.py b/pymeshio/pymeshio/mqo.py
new file mode 100755 (executable)
index 0000000..e9eee56
--- /dev/null
@@ -0,0 +1,473 @@
+#!BPY\r
+""" \r
+Name: 'Metasequoia(.mqo)...'\r
+Blender: 245\r
+Group: 'Import'\r
+Tooltip: 'Import from Metasequoia file format (.mqo)'\r
+"""\r
+__author__= 'ousttrue'\r
+__url__ = ["http://gunload.web.fc2.com/blender/"]\r
+__version__= '0.4 2009/11/25'\r
+__bpydoc__= '''\\r
+\r
+MQO Importer\r
+\r
+This script imports a mqo file.\r
+\r
+0.2 20080123: update.\r
+0.3 20091125: modify for linux.\r
+0.4 20100310: rewrite.\r
+0.5 20100311: create armature from mikoto bone.\r
+'''\r
+\r
+import os\r
+import sys\r
+import math\r
+\r
+\r
+class RGBA(object):\r
+    __slots__=['r', 'g', 'b', 'a']\r
+    def __init__(self, r=0, g=0, b=0, a=0):\r
+        self.r=r\r
+        self.g=g\r
+        self.b=b\r
+        self.a=a\r
+\r
+class Vector3(object):\r
+    __slots__=['x', 'y', 'z']\r
+    def __init__(self, x=0, y=0, z=0):\r
+        self.x=x\r
+        self.y=y\r
+        self.z=z\r
+\r
+    def __str__(self):\r
+        return "[%f, %f, %f]" % (self.x, self.y, self.z)\r
+\r
+    def __sub__(self, rhs):\r
+        return Vector3(self.x-rhs.x, self.y-rhs.y, self.z-rhs.z)\r
+\r
+    def getSqNorm(self):\r
+        return self.x*self.x + self.y*self.y + self.z*self.z\r
+\r
+    def getNorm(self):\r
+        return math.sqrt(self.getSqNorm())\r
+\r
+    def normalize(self):\r
+        factor=1.0/self.getNorm()\r
+        self.x*=factor\r
+        self.y*=factor\r
+        self.z*=factor\r
+        return self\r
+\r
+    def to_a(self):\r
+        return [self.x, self.y, self.z]\r
+\r
+    @staticmethod\r
+    def dot(lhs, rhs):\r
+        return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z\r
+\r
+    @staticmethod\r
+    def cross(lhs, rhs):\r
+        return Vector3(\r
+                lhs.y*rhs.z - rhs.y*lhs.z,\r
+                lhs.z*rhs.x - rhs.z*lhs.x,\r
+                lhs.x*rhs.y - rhs.x*lhs.y,\r
+                )\r
+\r
+\r
+class Vector2(object):\r
+    __slots__=['x', 'y']\r
+    def __init__(self, x=0, y=0):\r
+        self.x=x\r
+        self.y=y\r
+\r
+    def __str__(self):\r
+        return "[%f, %f]" % (self.x, self.y)\r
+\r
+    def __sub__(self, rhs):\r
+        return Vector3(self.x-rhs.x, self.y-rhs.y)\r
+\r
+    @staticmethod\r
+    def cross(lhs, rhs):\r
+        return lhs.x*rhs.y-lhs.y*rhs.x\r
+\r
+\r
+###############################################################################\r
+# MQO loader\r
+###############################################################################\r
+class Material(object):\r
+    __slots__=[\r
+            "name", "shader", "color", "diffuse", \r
+            "ambient", "emit", "specular", "power",\r
+            "tex",\r
+            ]\r
+    def __init__(self, name):\r
+        self.name=name\r
+        self.shader=3\r
+        self.color=RGBA(0.5, 0.5, 0.5, 1.0)\r
+        self.diffuse=1.0\r
+        self.ambient=0.0\r
+        self.emit=0.0\r
+        self.specular=0.0\r
+        self.power=5.0\r
+        self.tex=""\r
+\r
+    def getName(self): return self.name\r
+    def getTexture(self): return self.tex\r
+\r
+    def parse(self, line):\r
+        offset=0\r
+        while True:\r
+            leftParenthesis=line.find("(", offset)\r
+            if leftParenthesis==-1:\r
+                break\r
+            key=line[offset:leftParenthesis]\r
+            rightParenthesis=line.find(")", leftParenthesis+1)\r
+            if rightParenthesis==-1:\r
+                raise ValueError("assert")\r
+\r
+            param=line[leftParenthesis+1:rightParenthesis]\r
+            if key=="shader":\r
+                self.shader=int(param)\r
+            elif key=="col":\r
+                self.color=RGBA(*[float(e) for e in param.split()])\r
+            elif key=="dif":\r
+                self.diffuse=float(param)\r
+            elif key=="amb":\r
+                self.ambient=float(param)\r
+            elif key=="emi":\r
+                self.emit=float(param)\r
+            elif key=="spc":\r
+                self.specular=float(param)\r
+            elif key=="power":\r
+                self.power=float(param)\r
+            elif key=="tex":\r
+                self.tex=param[1:-1]\r
+            else:\r
+                print(\r
+                        "%s#parse" % self.name, \r
+                        "unknown key: %s" %  key\r
+                        )\r
+\r
+            offset=rightParenthesis+2\r
+\r
+    def __str__(self):\r
+        return "<Material %s shader: %d [%f, %f, %f, %f] %f>" % (\r
+                self.name, self.shader,\r
+                self.color[0], self.color[1], self.color[2], self.color[3],\r
+                self.diffuse)\r
+\r
+\r
+class Obj(object):\r
+    __slots__=["name", "depth", "folding", \r
+            "scale", "rotation", "translation",\r
+            "visible", "locking", "shading", "facet",\r
+            "color", "color_type", "mirror", "mirror_axis",\r
+            "vertices", "faces", "edges", "smoothing",\r
+            ]\r
+\r
+    def __init__(self, name):\r
+        self.name=name\r
+        self.vertices=[]\r
+        self.faces=[]\r
+        self.edges=[]\r
+        self.depth=0\r
+        self.folding=0\r
+        self.scale=[1, 1, 1]\r
+        self.rotation=[0, 0, 0]\r
+        self.translation=[0, 0, 0]\r
+        self.visible=15\r
+        self.locking=0\r
+        self.shading=0\r
+        self.facet=59.5\r
+        self.color=[1, 1, 1]\r
+        self.color_type=0\r
+        self.mirror=0\r
+        self.smoothing=0\r
+\r
+    def getName(self): return self.name\r
+\r
+    def addVertex(self, x, y, z):\r
+        self.vertices.append(Vector3(x, y, z))\r
+\r
+    def addFace(self, face):\r
+        if face.index_count==2:\r
+            self.edges.append(face)\r
+        else:\r
+            self.faces.append(face)\r
+\r
+    def __str__(self):\r
+        return "<Object %s, %d vertices, %d faces>" % (\r
+                self.name, len(self.vertices), len(self.faces))\r
+\r
+\r
+class Face(object):\r
+    __slots__=[\r
+            "index_count",\r
+            "indices", "material_index", "col", "uv",\r
+            ]\r
+    def __init__(self, index_count, line):\r
+        if index_count<2 or index_count>4:\r
+            raise ValueError("invalid vertex count: %d" % index_count)\r
+        self.material_index=0\r
+        self.col=[]\r
+        self.uv=[Vector2(0, 0)]*4\r
+        self.index_count=index_count\r
+        offset=0\r
+        while True:\r
+            leftParenthesis=line.find("(", offset)\r
+            if leftParenthesis==-1:\r
+                break\r
+            key=line[offset:leftParenthesis]\r
+            rightParenthesis=line.find(")", leftParenthesis+1)\r
+            if rightParenthesis==-1:\r
+                raise ValueError("assert")\r
+            params=line[leftParenthesis+1:rightParenthesis].split()\r
+            if key=="V":\r
+                self.indices=[int(e) for e in params]\r
+            elif key=="M":\r
+                self.material_index=int(params[0])\r
+            elif key=="UV":\r
+                uv_list=[float(e) for e in params]\r
+                self.uv=[]\r
+                for i in range(0, len(uv_list), 2):\r
+                    self.uv.append(Vector2(uv_list[i], uv_list[i+1]))\r
+            elif key=="COL":\r
+                for n in params:\r
+                    d=int(n)\r
+                    # R\r
+                    d, m=divmod(d, 256)\r
+                    self.col.append(m)\r
+                    # G\r
+                    d, m=divmod(d, 256)\r
+                    self.col.append(m)\r
+                    # B\r
+                    d, m=divmod(d, 256)\r
+                    self.col.append(m)\r
+                    # A\r
+                    d, m=divmod(d, 256)\r
+                    self.col.append(m)\r
+            else:\r
+                print("Face#__init__:unknown key: %s" % key)\r
+\r
+            offset=rightParenthesis+2\r
+\r
+    def getIndex(self, i): return self.indices[i]\r
+    def getUV(self, i): return self.uv[i] if i<len(self.uv) else Vector2(0, 0)\r
+\r
+\r
+def withio(method):\r
+    def new(self, path):\r
+        self.io=open(path, encoding='cp932')\r
+        result=method(self)\r
+        self.io=None\r
+        return result\r
+    return new\r
+\r
+\r
+class IO(object):\r
+    __slots__=[\r
+            "has_mikoto",\r
+            "eof", "io", "lines",\r
+            "materials", "objects",\r
+            ]\r
+    def __init__(self):\r
+        self.has_mikoto=False\r
+        self.eof=False\r
+        self.io=None\r
+        self.lines=0\r
+        self.materials=[]\r
+        self.objects=[]\r
+\r
+    def __str__(self):\r
+        return "<MQO %d lines, %d materials, %d objects>" % (\r
+                self.lines, len(self.materials), len(self.objects))\r
+\r
+    def getline(self):\r
+        line=self.io.readline()\r
+        self.lines+=1\r
+        if line=="":\r
+            self.eof=True\r
+            return None\r
+        return line.strip()\r
+\r
+    def printError(self, method, msg):\r
+        print("%s:%s:%d" % (method, msg, self.lines))\r
+\r
+    @withio\r
+    def read(self):\r
+        line=self.getline()\r
+        if line!="Metasequoia Document":\r
+            print("invalid signature")\r
+            return False\r
+\r
+        line=self.getline()\r
+        if line!="Format Text Ver 1.0":\r
+            print("unknown version: %s" % line)\r
+\r
+        while True:\r
+            line=self.getline()\r
+            if line==None:\r
+                # eof\r
+                break;\r
+            if line=="":\r
+                # empty line\r
+                continue\r
+\r
+            tokens=line.split()\r
+            key=tokens[0]\r
+\r
+            if key=="Eof":\r
+                return True\r
+            elif key=="Scene":\r
+                if not self.readChunk():\r
+                    return False\r
+            elif key=="Material":\r
+                if not self.readMaterial():\r
+                    return False\r
+            elif key=="Object":\r
+                firstQuote=line.find('"')\r
+                secondQuote=line.find('"', firstQuote+1)\r
+                if not self.readObject(line[firstQuote+1:secondQuote]):\r
+                    return False\r
+            elif key=="BackImage":\r
+                if not self.readChunk():\r
+                    return False\r
+            elif key=="IncludeXml":\r
+                firstQuote=line.find('"')\r
+                secondQuote=line.find('"', firstQuote+1)\r
+                print("IncludeXml", line[firstQuote+1:secondQuote])\r
+            else:\r
+                print("unknown key: %s" % key)\r
+                if not self.readChunk():\r
+                    return False\r
+\r
+        self.printError("parse", "invalid eof")\r
+        return False\r
+\r
+    def readObject(self, name):\r
+        obj=Obj(name)\r
+        if name.startswith('bone'):\r
+            self.has_mikoto=True\r
+        self.objects.append(obj)\r
+        while(True):\r
+            line=self.getline()\r
+            if line==None:\r
+                # eof\r
+                break;\r
+            if line=="":\r
+                # empty line\r
+                continue\r
+\r
+            if line=="}":\r
+                return True\r
+            else:\r
+                tokens=line.split()\r
+                key=tokens[0]\r
+                if key=="vertex":\r
+                    if not self.readVertex(obj):\r
+                        return False\r
+                elif key=="face":\r
+                    if not self.readFace(obj):\r
+                        return False\r
+                elif key=="depth":\r
+                    obj.depth=int(tokens[1])\r
+                else:\r
+                    print(\r
+                            "%s#readObject" % name,\r
+                            "unknown key: %s" % name\r
+                            )\r
+\r
+        self.printError("readObject", "invalid eof")\r
+        return False\r
+\r
+    def readFace(self, obj):\r
+        while(True):\r
+            line=self.getline()\r
+            if line==None:\r
+                # eof\r
+                break;\r
+            if line=="":\r
+                # empty line\r
+                continue\r
+\r
+            if line=="}":\r
+                return True\r
+            else:\r
+                # face\r
+                tokens=line.split(' ', 1)\r
+                try:\r
+                    obj.addFace(Face(int(tokens[0]), tokens[1]))\r
+                except ValueError as ex:\r
+                    self.printError("readFace", ex)\r
+                    #return False\r
+\r
+        self.printError("readFace", "invalid eof")\r
+        return False\r
+\r
+    def readVertex(self, obj):\r
+        while(True):\r
+            line=self.getline()\r
+            if line==None:\r
+                # eof\r
+                break;\r
+            if line=="":\r
+                # empty line\r
+                continue\r
+\r
+            if line=="}":\r
+                return True\r
+            else:\r
+                # vertex\r
+                obj.addVertex(*[float(v) for v in line.split()])\r
+\r
+        self.printError("readVertex", "invalid eof")\r
+        return False\r
+\r
+    def readMaterial(self):\r
+        while(True):\r
+            line=self.getline()\r
+            if line==None:\r
+                # eof\r
+                break;\r
+            if line=="":\r
+                # empty line\r
+                continue\r
+\r
+            if line=="}":\r
+                return True\r
+            else:\r
+                # material\r
+                secondQuaote=line.find('"', 1)                \r
+                material=Material(line[1:secondQuaote])\r
+                try:\r
+                    material.parse(line[secondQuaote+2:])\r
+                except ValueError as ex:\r
+                    self.printError("readMaterial", ex)\r
+\r
+                self.materials.append(material)\r
+\r
+        self.printError("readMaterial", "invalid eof")\r
+        return False\r
+\r
+    def readChunk(self):\r
+        level=1\r
+        while(True):\r
+            line=self.getline()\r
+            if line==None:\r
+                # eof\r
+                break;\r
+            if line=="":\r
+                # empty line\r
+                continue\r
+\r
+            if line=="}":\r
+                level-=1\r
+                if level==0:\r
+                    return True\r
+            elif line.find("{")!=-1:\r
+                level+=1\r
+\r
+        self.printError("readChunk", "invalid eof")\r
+        return False\r
+\r