OSDN Git Service

implement converter
[meshio/pymeshio.git] / pymeshio / pmx / __init__.py
index c1614af..7afe5f2 100644 (file)
@@ -1,10 +1,22 @@
 #!/usr/bin/env python\r
 # coding: utf-8\r
 """\r
-pmx file io library.\r
+========================\r
+MikuMikuDance PMX format\r
+========================\r
+\r
+file format\r
+~~~~~~~~~~~\r
+* PMDEditor's Lib/PMX仕様/PMX仕様.txt\r
+\r
+specs\r
+~~~~~\r
+* textencoding: unicode\r
+* coordinate: left handed y-up(DirectX)\r
+* uv origin: \r
+* face: only triangle\r
+* backculling: \r
 \r
-pmx file format:\r
-    PMDEditor's Lib/PMX仕様/PMX仕様.txt\r
 """\r
 __author__="ousttrue"\r
 __license__="zlib"\r
@@ -18,7 +30,42 @@ from pymeshio import common
 \r
 \r
 \r
-class Ik(object):\r
+class DifferenceException(Exception):\r
+    pass\r
+\r
+\r
+class Diff(object):\r
+    def _diff(self, rhs, key):\r
+        l=getattr(self, key)\r
+        r=getattr(rhs, key)\r
+        if l!=r:\r
+            print(l)\r
+            print(r)\r
+            raise DifferenceException(key)\r
+\r
+    def _diff_array(self, rhs, key):\r
+        la=getattr(self, key)\r
+        ra=getattr(rhs, key)\r
+        if len(la)!=len(la):\r
+            raise DifferenceException(key)\r
+        for i, (l, r) in enumerate(zip(la, ra)):\r
+            if isinstance(l, Diff):\r
+                try:\r
+                    l.diff(r)\r
+                except DifferenceException as e:\r
+                    print(i)\r
+                    print(l)\r
+                    print(r)\r
+                    raise DifferenceException("{0}: {1}".format(key, e.message))\r
+            else:\r
+                if l!=r:\r
+                    print(i)\r
+                    print(l)\r
+                    print(r)\r
+                    raise DifferenceException("{0}".format(key))\r
+\r
+\r
+class Ik(Diff):\r
     """ik info\r
     """\r
     __slots__=[\r
@@ -27,14 +74,28 @@ class Ik(object):
             'limit_radian',\r
             'link',\r
             ]\r
-    def __init__(self, target_index, loop, limit_radian):\r
+    def __init__(self, target_index, loop, limit_radian, link=[]):\r
         self.target_index=target_index\r
         self.loop=loop\r
         self.limit_radian=limit_radian\r
-        self.link=[]\r
+        self.link=link\r
+\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.target_index==rhs.target_index\r
+                and self.loop==rhs.loop\r
+                and self.limit_radian==rhs.limit_radian\r
+                and self.link==rhs.link\r
+                )\r
 \r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'target_index')\r
+        self._diff(rhs, 'loop')\r
+        self._diff(rhs, 'limit_radian')\r
+        self._diff_array(rhs, 'link')\r
 \r
-class IkLink(object):\r
+\r
+class IkLink(Diff):\r
     """ik link info\r
     """\r
     __slots__=[\r
@@ -43,14 +104,28 @@ class IkLink(object):
             'limit_min',\r
             'limit_max',\r
             ]\r
-    def __init__(self, bone_index, limit_angle):\r
+    def __init__(self, bone_index, limit_angle, limit_min=common.Vector3(), limit_max=common.Vector3()):\r
         self.bone_index=bone_index\r
         self.limit_angle=limit_angle\r
-        self.limit_min=None\r
-        self.limit_max=None\r
+        self.limit_min=limit_min\r
+        self.limit_max=limit_max\r
+\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.bone_index==rhs.bone_index\r
+                and self.limit_angle==rhs.limit_angle\r
+                and self.limit_min==rhs.limit_min\r
+                and self.limit_max==rhs.limit_max\r
+                )\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'bone_index')\r
+        self._diff(rhs, 'limit_angle')\r
+        self._diff(rhs, 'limit_min')\r
+        self._diff(rhs, 'limit_max')\r
 \r
 \r
-class Bone(object):\r
+class Bone(Diff):\r
     """material\r
 \r
     Bone: see __init__\r
@@ -63,7 +138,7 @@ class Bone(object):
             'layer',\r
             'flag',\r
 \r
-            'tail_positoin',\r
+            'tail_position',\r
             'tail_index',\r
             'effect_index',\r
             'effect_factor',\r
@@ -79,14 +154,65 @@ class Bone(object):
             position,\r
             parent_index,\r
             layer,\r
-            flag\r
+            flag,\r
+            tail_position=common.Vector3(),\r
+            tail_index=-1,\r
+            effect_index=-1,\r
+            effect_factor=0.0,\r
+            fixed_axis=common.Vector3(),\r
+            local_x_vector=common.Vector3(),\r
+            local_z_vector=common.Vector3(),\r
+            external_key=-1,\r
+            ik=None\r
             ):\r
-        self.name=name,\r
+        self.name=name\r
         self.english_name=english_name\r
         self.position=position\r
         self.parent_index=parent_index\r
         self.layer=layer\r
         self.flag=flag\r
+        self.tail_position=tail_position\r
+        self.tail_index=tail_index\r
+        self.effect_index=effect_index\r
+        self.effect_factor=effect_factor\r
+        self.fixed_axis=fixed_axis\r
+        self.local_x_vector=local_x_vector\r
+        self.local_z_vector=local_z_vector\r
+        self.external_key=external_key\r
+        self.ik=ik\r
+\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.name==rhs.name\r
+                and self.english_name==rhs.english_name\r
+                and self.position==rhs.position\r
+                and self.parent_index==rhs.parent_index\r
+                and self.layer==rhs.layer\r
+                and self.flag==rhs.flag\r
+                )\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'name')\r
+        self._diff(rhs, 'english_name')\r
+        self._diff(rhs, 'position')\r
+        self._diff(rhs, 'parent_index')\r
+        #self._diff(rhs, 'layer')\r
+        self._diff(rhs, 'flag')\r
+        self._diff(rhs, 'tail_position')\r
+        self._diff(rhs, 'tail_index')\r
+        #self._diff(rhs, 'effect_index')\r
+        #self._diff(rhs, 'effect_factor')\r
+        #self._diff(rhs, 'fixed_axis')\r
+        self._diff(rhs, 'local_x_vector')\r
+        self._diff(rhs, 'local_z_vector')\r
+        self._diff(rhs, 'external_key')\r
+        if self.ik and rhs.ik:\r
+            self.ik.diff(rhs.ik)\r
+        else:\r
+            self._diff(rhs, 'ik')\r
 \r
     def getConnectionFlag(self):\r
         return self.flag & 0x0001\r
@@ -110,7 +236,7 @@ class Bone(object):
         return (self.flag &  0x2000) >> 13\r
 \r
  \r
-class Material(object):\r
+class Material(Diff):\r
     """material\r
 \r
     Attributes: see __init__\r
@@ -119,7 +245,7 @@ class Material(object):
             'name',\r
             'english_name',\r
             'diffuse_color',\r
-            'diffuse_alpha',\r
+            'alpha',\r
             'specular_color',\r
             'specular_factor',\r
             'ambient_color',\r
@@ -127,8 +253,8 @@ class Material(object):
             'edge_color',\r
             'edge_size',\r
             'texture_index',\r
-            'sphia_texture_index',\r
-            'sphia_mode',\r
+            'sphere_texture_index',\r
+            'sphere_mode',\r
             'toon_sharing_flag',\r
             'toon_texture_index',\r
             'comment',\r
@@ -138,22 +264,25 @@ class Material(object):
             name,\r
             english_name,\r
             diffuse_color,\r
-            diffuse_alpha,\r
-            specular_color,\r
+            alpha,\r
             specular_factor,\r
+            specular_color,\r
             ambient_color,\r
             flag,\r
             edge_color,\r
             edge_size,\r
             texture_index,\r
-            sphia_texture_index,\r
-            sphia_mode,\r
-            toon_sharing_flag\r
+            sphere_texture_index,\r
+            sphere_mode,\r
+            toon_sharing_flag,\r
+            toon_texture_index=0,\r
+            comment=common.unicode(""),\r
+            vertex_count=0,\r
             ):\r
         self.name=name\r
         self.english_name=english_name\r
         self.diffuse_color=diffuse_color\r
-        self.diffuse_alpha=diffuse_alpha\r
+        self.alpha=alpha\r
         self.specular_color=specular_color\r
         self.specular_factor=specular_factor\r
         self.ambient_color=ambient_color\r
@@ -161,13 +290,55 @@ class Material(object):
         self.edge_color=edge_color\r
         self.edge_size=edge_size\r
         self.texture_index=texture_index\r
-        self.sphia_texture_index=sphia_texture_index\r
-        self.sphia_mode=sphia_mode\r
+        self.sphere_texture_index=sphere_texture_index\r
+        self.sphere_mode=sphere_mode\r
         self.toon_sharing_flag=toon_sharing_flag\r
-        #\r
-        self.toon_texture_index=None\r
-        self.comment=''\r
-        self.vertex_count=0\r
+        self.toon_texture_index=toon_texture_index\r
+        self.comment=comment\r
+        self.vertex_count=vertex_count\r
+\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.name==rhs.name\r
+                and self.english_name==rhs.english_name\r
+                and self.diffuse_color==rhs.diffuse_color\r
+                and self.alpha==rhs.alpha\r
+                and self.specular_color==rhs.specular_color\r
+                and self.specular_factor==rhs.specular_factor\r
+                and self.ambient_color==rhs.ambient_color\r
+                and self.flag==rhs.flag\r
+                and self.edge_color==rhs.edge_color\r
+                and self.edge_size==rhs.edge_size\r
+                and self.texture_index==rhs.texture_index\r
+                and self.sphere_texture_index==rhs.sphere_texture_index\r
+                and self.sphere_mode==rhs.sphere_mode\r
+                and self.toon_sharing_flag==rhs.toon_sharing_flag\r
+                and self.toon_texture_index==rhs.toon_texture_index\r
+                and self.comment==rhs.comment\r
+                and self.vertex_count==rhs.vertex_count\r
+                )\r
+\r
+    def diff(self, rhs):\r
+        #self._diff(rhs, "name")\r
+        self._diff(rhs, "english_name")\r
+        self._diff(rhs, "diffuse_color")\r
+        self._diff(rhs, "alpha")\r
+        self._diff(rhs, "specular_color")\r
+        self._diff(rhs, "specular_factor")\r
+        self._diff(rhs, "ambient_color")\r
+        self._diff(rhs, "flag")\r
+        self._diff(rhs, "edge_color")\r
+        self._diff(rhs, "edge_size")\r
+        self._diff(rhs, "texture_index")\r
+        self._diff(rhs, "sphere_texture_index")\r
+        self._diff(rhs, "sphere_mode")\r
+        self._diff(rhs, "toon_sharing_flag")\r
+        self._diff(rhs, "toon_texture_index")\r
+        self._diff(rhs, "comment")\r
+        self._diff(rhs, "vertex_count")\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
 \r
     def __str__(self):\r
         return ("<pmx.Material {name}>".format(\r
@@ -175,11 +346,7 @@ class Material(object):
             ))\r
 \r
 \r
-class Deform(object):\r
-    pass\r
-\r
-\r
-class Bdef1(object):\r
+class Bdef1(Diff):\r
     """bone deform. use a weight\r
 \r
     Attributes: see __init__\r
@@ -188,8 +355,17 @@ class Bdef1(object):
     def __init__(self, index0):\r
         self.index0=index0\r
 \r
+    def __str__(self):\r
+        return "<Bdef1 {0}>".format(self.index0)\r
+\r
+    def __eq__(self, rhs):\r
+        return self.index0==rhs.index0\r
 \r
-class Bdef2(object):\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+\r
+class Bdef2(Diff):\r
     """bone deform. use two weights\r
 \r
     Attributes: see __init__\r
@@ -203,11 +379,38 @@ class Bdef2(object):
         self.index1=index1\r
         self.weight0=weight0\r
 \r
+    def __str__(self):\r
+        return "<Bdef2 {0}, {1}, {2}>".format(self.index0, self.index1, self.weight0)\r
 \r
-class Vertex(object):\r
-    """pmx vertex\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.index0==rhs.index0\r
+                and self.index1==rhs.index1\r
+                #and self.weight0==rhs.weight0\r
+                and abs(self.weight0-rhs.weight0)<1e-5\r
+                )\r
 \r
-    Attributes: see __init__\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+\r
+class Vertex(Diff):\r
+    """\r
+    ==========\r
+    pmx vertex\r
+    ==========\r
+\r
+    :IVariables:\r
+        position\r
+            Vector3\r
+        normal \r
+            Vector3\r
+        uv \r
+            Vector2\r
+        deform\r
+            Bdef1, Bdef2 or Bdef4\r
+        edge_factor\r
+            float\r
     """\r
     __slots__=[ 'position', 'normal', 'uv', 'deform', 'edge_factor' ]\r
     def __init__(self, \r
@@ -222,8 +425,32 @@ class Vertex(object):
         self.deform=deform\r
         self.edge_factor=edge_factor\r
 \r
-\r
-class Morph(object):\r
+    def __str__(self):\r
+        return "<Vertex position:{0}, normal:{1}, uv:{2}, deform:{3}, edge:{4}".format(\r
+                self.position, self.normal, self.uv, self.deform, self.edge_factor\r
+                )\r
+\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.position==rhs.position\r
+                and self.normal==rhs.normal\r
+                and self.uv==rhs.uv\r
+                and self.deform==rhs.deform\r
+                and self.edge_factor==rhs.edge_factor\r
+                )\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, "position")\r
+        self._diff(rhs, "normal")\r
+        self._diff(rhs, "uv")\r
+        self._diff(rhs, "deform")\r
+        self._diff(rhs, "edge_factor")\r
+\r
+\r
+class Morph(Diff):\r
     """pmx morph\r
 \r
     Attributes:\r
@@ -247,8 +474,27 @@ class Morph(object):
         self.morph_type=morph_type\r
         self.offsets=[]\r
 \r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.name==rhs.name\r
+                and self.english_name==rhs.english_name\r
+                and self.panel==rhs.panel\r
+                and self.morph_type==rhs.morph_type\r
+                and self.offsets==rhs.offsets\r
+                )\r
 \r
-class VerexMorphOffset(object):\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'name')\r
+        self._diff(rhs, 'english_name')\r
+        self._diff(rhs, 'panel')\r
+        self._diff(rhs, 'morph_type')\r
+        self._diff_array(rhs, 'offsets')\r
+\r
+\r
+class VerexMorphOffset(Diff):\r
     """pmx vertex morph offset\r
 \r
     Attributes:\r
@@ -263,8 +509,21 @@ class VerexMorphOffset(object):
         self.vertex_index=vertex_index\r
         self.position_offset=position_offset\r
 \r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.vertex_index==rhs.vertex_index \r
+                and self.position_offset==rhs.position_offset\r
+                )\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
 \r
-class DisplaySlot(object):\r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'name')\r
+        self._diff(rhs, 'english_name')\r
+\r
+\r
+class DisplaySlot(Diff):\r
     """pmx display slot\r
 \r
     Attributes:\r
@@ -285,33 +544,25 @@ class DisplaySlot(object):
         self.special_flag=special_flag\r
         self.refrences=[]\r
 \r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.name==rhs.name\r
+                and self.english_name==rhs.english_name\r
+                and self.special_flag==rhs.special_flag\r
+                and self.refrences==rhs.refrences\r
+                )\r
 \r
-class Shape(object):\r
-    pass\r
-\r
-\r
-class SphereShape(Shape):\r
-    __slots__=['radius']\r
-    def __init__(self, radius):\r
-        self.radius=radius\r
-\r
-\r
-class CapsuleShape(Shape):\r
-    __slots__=['short_radius', 'long_radius']\r
-    def __init__(self, short_radius, long_radius): \r
-        self.short_radius=short_radius\r
-        self.long_radius=long_radius\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
 \r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'name')\r
+        self._diff(rhs, 'english_name')\r
+        self._diff(rhs, 'special_flag')\r
+        self._diff_array(rhs, 'refrences')\r
 \r
-class BoxShape(Shape):\r
-    __slots__=['x', 'y', 'z']\r
-    def __init__(self, x, y, z):\r
-        self.x=x\r
-        self.y=y\r
-        self.z=z\r
 \r
-\r
-class RigidBodyParam(object):\r
+class RigidBodyParam(Diff):\r
     """pmx rigidbody param(for bullet)\r
 \r
     Attributes:\r
@@ -336,8 +587,27 @@ class RigidBodyParam(object):
         self.restitution=restitution\r
         self.friction=friction\r
 \r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.mass==rhs.mass\r
+                and self.linear_damping==rhs.linear_damping\r
+                and self.angular_damping==rhs.angular_damping\r
+                and self.restitution==rhs.restitution\r
+                and self.friction==rhs.friction\r
+                )\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'mass')\r
+        self._diff(rhs, 'linear_damping')\r
+        self._diff(rhs, 'angular_damping')\r
+        self._diff_array(rhs, 'restitution')\r
+        self._diff_array(rhs, 'friction')\r
 \r
-class RigidBody(object):\r
+\r
+class RigidBody(Diff):\r
     """pmx rigidbody\r
 \r
     Attributes:\r
@@ -345,7 +615,7 @@ class RigidBody(object):
         english_name: \r
         bone_index:\r
         collision_group:\r
-        no_collision_flag:\r
+        no_collision_group:\r
         shape:\r
         param:\r
         mode:\r
@@ -355,8 +625,11 @@ class RigidBody(object):
             'english_name',\r
             'bone_index',\r
             'collision_group',\r
-            'no_collision_flag',\r
-            'shape',\r
+            'no_collision_group',\r
+            'shape_type',\r
+            'shape_size',\r
+            'shape_position',\r
+            'shape_rotation',\r
             'param',\r
             'mode',\r
             ]\r
@@ -365,7 +638,7 @@ class RigidBody(object):
             english_name,\r
             bone_index,\r
             collision_group,\r
-            no_collision_flag,\r
+            no_collision_group,\r
             shape_type,\r
             shape_size,\r
             shape_position,\r
@@ -381,23 +654,47 @@ class RigidBody(object):
         self.english_name=english_name\r
         self.bone_index=bone_index\r
         self.collision_group=collision_group\r
-        self.no_collision_flag=no_collision_flag\r
-        if shape_type==0:\r
-            self.shape=SphereShape(shape_size.x)\r
-        elif shape_type==1:\r
-            self.shape=BoxShape(shape_size.x, shape_size.y, shape_size.z)\r
-        elif shape_type==2:\r
-            self.shape=CapsuleShape(shape_size.x, shape_size.y)\r
-        else:\r
-            raise pymeshio.common.ParseException(\r
-                    "unknown shape_type: {0}".format(shape_type))\r
+        self.no_collision_group=no_collision_group\r
+        self.shape_type=shape_type\r
+        self.shape_size=shape_size\r
+        self.shape_position=shape_position\r
+        self.shape_rotation=shape_rotation\r
         self.param=RigidBodyParam(mass,\r
                 linear_damping, angular_damping,\r
                 restitution, friction)\r
         self.mode=mode\r
 \r
-\r
-class Joint(object):\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.name==rhs.name\r
+                and self.english_name==rhs.english_name\r
+                and self.bone_index==rhs.bone_index\r
+                and self.collision_group==rhs.collision_group\r
+                and self.no_collision_group==rhs.no_collision_group\r
+                and self.shape_type==rhs.shape_type\r
+                and self.shape_size==rhs.shape_size\r
+                and self.param==rhs.param\r
+                and self.mode==rhs.mode\r
+                )\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'name')\r
+        self._diff(rhs, 'english_name')\r
+        self._diff(rhs, 'bone_index')\r
+        self._diff(rhs, 'collision_group')\r
+        self._diff(rhs, 'no_collision_group')\r
+        self._diff(rhs, 'shape_type')\r
+        self._diff(rhs, 'shape_size')\r
+        self._diff(rhs, 'shape_position')\r
+        self._diff(rhs, 'shape_rotation')\r
+        self._diff(rhs, 'param')\r
+        self._diff(rhs, 'mode')\r
+\r
+\r
+class Joint(Diff):\r
     """pmx joint\r
 \r
     Attributes:\r
@@ -457,31 +754,81 @@ class Joint(object):
         self.spring_constant_translation=spring_constant_translation\r
         self.spring_constant_rotation=spring_constant_rotation\r
 \r
-\r
-class Model(object):\r
-    """pmx data representation\r
-\r
-    Attributes:\r
-        version: pmx version(expected 2.0)\r
-        name: \r
-        english_name: \r
-        comment: \r
-        english_comment: \r
-        vertices:\r
-        textures:\r
-        materials:\r
-        bones:\r
-        morph:\r
-        display_slots:\r
-        rigidbodies:\r
-        joints:\r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.name==rhs.name\r
+                and self.english_name==rhs.english_name\r
+                and self.joint_type==rhs.joint_type\r
+                and self.rigidbody_index_a==rhs.rigidbody_index_a\r
+                and self.rigidbody_index_b==rhs.rigidbody_index_b\r
+                and self.position==rhs.position\r
+                and self.rotation==rhs.rotation\r
+                and self.translation_limit_min==rhs.translation_limit_min\r
+                and self.translation_limit_max==rhs.translation_limit_max\r
+                and self.rotation_limit_min==rhs.rotation_limit_min\r
+                and self.rotation_limit_max==rhs.rotation_limit_max\r
+                and self.spring_constant_translation==rhs.spring_constant_translation\r
+                and self.spring_constant_rotation==rhs.spring_constant_rotation\r
+                )\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, 'name')\r
+        self._diff(rhs, 'joint_type')\r
+        self._diff(rhs, 'rigidbody_index_a')\r
+        self._diff(rhs, 'rigidbody_index_b')\r
+        self._diff(rhs, 'position')\r
+        self._diff(rhs, 'rotation')\r
+        self._diff(rhs, 'translation_limit_min')\r
+        self._diff(rhs, 'translation_limit_max')\r
+        self._diff(rhs, 'rotation_limit_min')\r
+        self._diff(rhs, 'rotation_limit_max')\r
+        self._diff(rhs, 'spring_constant_translation')\r
+        self._diff(rhs, 'spring_constant_rotation')\r
+\r
+\r
+class Model(Diff):\r
+    """\r
+    ==========\r
+    pmx model\r
+    ==========\r
+\r
+    :IVariables:\r
+        version\r
+            pmx version(expected 2.0)\r
+        name \r
+            model name\r
+        english_name \r
+            model name\r
+        comment \r
+            comment\r
+        english_comment \r
+            comment\r
+        vertices\r
+            vertex list\r
+        textures\r
+            texture list\r
+        materials\r
+            material list\r
+        bones\r
+            bone list\r
+        morph\r
+            morph list\r
+        display_slots\r
+            display list for bone/morph grouping\r
+        rigidbodies\r
+            bullet physics rigidbody list\r
+        joints\r
+            bullet physics joint list\r
     """\r
     __slots__=[\r
-            'version', # pmx version\r
-            'name', # model name\r
-            'english_name', # model name in english\r
-            'comment', # model comment\r
-            'english_comment', # model comment in english\r
+            'version',\r
+            'name',\r
+            'english_name',\r
+            'comment',\r
+            'english_comment',\r
             'vertices',\r
             'indices',\r
             'textures',\r
@@ -492,7 +839,7 @@ class Model(object):
             'rigidbodies',\r
             'joints',\r
             ]\r
-    def __init__(self, version):\r
+    def __init__(self, version=2.0):\r
         self.version=version\r
         self.name=''\r
         self.english_name=''\r
@@ -503,6 +850,8 @@ class Model(object):
         self.textures=[]\r
         self.materials=[]\r
         self.bones=[]\r
+        self.morphs=[]\r
+        self.display_slots=[]\r
         self.rigidbodies=[]\r
         self.joints=[]\r
 \r
@@ -513,3 +862,40 @@ class Model(object):
             vertices=len(self.vertices)\r
             ))\r
 \r
+    def __eq__(self, rhs):\r
+        return (\r
+                self.version==rhs.version\r
+                and self.name==rhs.name\r
+                and self.english_name==rhs.english_name\r
+                and self.comment==rhs.comment\r
+                and self.english_comment==rhs.english_comment\r
+                and self.vertices==rhs.vertices\r
+                and self.indices==rhs.indices\r
+                and self.textures==rhs.textures\r
+                and self.materials==rhs.materials\r
+                and self.bones==rhs.bones\r
+                and self.morphs==rhs.morphs\r
+                and self.display_slots==rhs.display_slots\r
+                and self.rigidbodies==rhs.rigidbodies\r
+                and self.joints==rhs.joints\r
+                )\r
+\r
+    def __ne__(self, rhs):\r
+        return not self.__eq__(rhs)\r
+\r
+    def diff(self, rhs):\r
+        self._diff(rhs, "version")\r
+        self._diff(rhs, "name")\r
+        self._diff(rhs, "english_name")\r
+        self._diff(rhs, "comment")\r
+        self._diff(rhs, "english_comment")\r
+        self._diff_array(rhs, "vertices")\r
+        self._diff_array(rhs, "indices")\r
+        self._diff_array(rhs, "textures")\r
+        self._diff_array(rhs, "materials")\r
+        self._diff_array(rhs, "bones")\r
+        self._diff_array(rhs, "morphs")\r
+        self._diff_array(rhs, "display_slots")\r
+        self._diff_array(rhs, "rigidbodies")\r
+        self._diff_array(rhs, "joints")\r
+\r