OSDN Git Service

implement pmx.writer
authorousttrue <ousttrue@gmail.com>
Mon, 3 Oct 2011 17:20:50 +0000 (02:20 +0900)
committerousttrue <ousttrue@gmail.com>
Mon, 3 Oct 2011 17:20:50 +0000 (02:20 +0900)
pymeshio/common.py
pymeshio/pmd/writer.py
pymeshio/pmx/__init__.py
pymeshio/pmx/reader.py
pymeshio/pmx/writer.py [new file with mode: 0644]
test/pmx_test.py

index 45a7ff0..7177506 100644 (file)
@@ -243,6 +243,9 @@ class RGBA(object):
         self.b=b\r
         self.a=a\r
 \r
+    def __eq__(self, rhs):\r
+        return self.r==rhs.r and self.g==rhs.g and self.b==rhs.b and self.a==rhs.a\r
+\r
     def __getitem__(self, key):\r
         if key==0:\r
             return self.r\r
@@ -331,11 +334,15 @@ class BinaryReader(object):
                 )\r
 \r
 \r
+class WriteException(Exception):\r
+    pass\r
+\r
+\r
 class BinaryWriter(object):\r
     def __init__(self, ios):\r
         self.ios=ios\r
 \r
-    def write_text(self, v, size=None):\r
+    def write_bytes(self, v, size=None):\r
         if size:\r
             self.ios.write(struct.pack("={0}s".format(size), v))\r
         else:\r
@@ -363,4 +370,7 @@ class BinaryWriter(object):
     def write_rgb(self, v):\r
         self.ios.write(struct.pack("=3f", v.r, v.g, v.b))\r
 \r
+    def write_rgba(self, v):\r
+        self.ios.write(struct.pack("=4f", v.r, v.g, v.b, v.a))\r
+\r
 \r
index 187f59d..0e7ec0d 100644 (file)
@@ -32,14 +32,14 @@ class Writer(common.BinaryWriter):
             self.write_uint(m.toon_index, 1)\r
             self.write_uint(m.edge_flag, 1)\r
             self.write_uint(m.vertex_count, 4)\r
-            self.write_text(m.texture_file, 20)\r
+            self.write_bytes(m.texture_file, 20)\r
 \r
     def write_bones(self, bones):\r
         self.write_uint(len(bones), 2)\r
         sBone=struct.Struct("=20sHHBH3f")\r
         assert(sBone.size==39)\r
         for b in bones:\r
-            self.write_text(b.name, 20)\r
+            self.write_bytes(b.name, 20)\r
             self.write_uint(b.parent_index, 2)\r
             self.write_uint(b.tail_index, 2)\r
             self.write_uint(b.type, 1)\r
@@ -59,7 +59,7 @@ class Writer(common.BinaryWriter):
     def write_morphs(self, morphs):\r
         self.write_uint(len(morphs), 2)\r
         for morph in morphs:\r
-            self.write_text(morph.name, 20)\r
+            self.write_bytes(morph.name, 20)\r
             self.write_uint(len(morph.indices), 4)\r
             self.write_uint(morph.type, 1)\r
             for i, v in zip(morph.indices, morph.pos_list):\r
@@ -73,7 +73,7 @@ class Writer(common.BinaryWriter):
     def write_bone_group_list(self, bone_group_list):\r
         self.write_uint(len(bone_group_list), 1)\r
         for g in bone_group_list:\r
-            self.write_text(g.name, 50)\r
+            self.write_bytes(g.name, 50)\r
 \r
     def write_bone_display_list(self, bone_display_list):\r
         self.write_uint(len(bone_display_list), 4)\r
@@ -84,7 +84,7 @@ class Writer(common.BinaryWriter):
     def write_rigidbodies(self, rigidbodies):\r
         self.write_uint(len(rigidbodies), 4)\r
         for r in rigidbodies:\r
-            self.write_text(r.name, 20)\r
+            self.write_bytes(r.name, 20)\r
             self.write_uint(r.bone_index, 2)\r
             self.write_uint(r.collision_group, 1)\r
             self.write_uint(r.no_collision_group, 2)\r
@@ -102,7 +102,7 @@ class Writer(common.BinaryWriter):
     def write_joints(self, joints):\r
         self.write_uint(len(joints), 4)\r
         for j in joints:\r
-            self.write_text(j.name, 20)\r
+            self.write_bytes(j.name, 20)\r
             self.write_uint(j.rigidbody_index_a, 4)\r
             self.write_uint(j.rigidbody_index_b, 4)\r
             self.write_vector3(j.position)\r
@@ -119,10 +119,10 @@ def write(ios, model):
     assert(isinstance(ios, io.IOBase))\r
     assert(isinstance(model, pmd.Model))\r
     writer=Writer(ios)\r
-    writer.write_text(b"Pmd")\r
+    writer.write_bytes(b"Pmd")\r
     writer.write_float(model.version)\r
-    writer.write_text(model.name, 20)\r
-    writer.write_text(model.comment, 256)\r
+    writer.write_bytes(model.name, 20)\r
+    writer.write_bytes(model.comment, 256)\r
     writer.write_veritices(model.vertices)\r
     writer.write_indices(model.indices)\r
     writer.write_materials(model.materials)\r
@@ -134,18 +134,18 @@ def write(ios, model):
     writer.write_bone_display_list(model.bone_display_list)\r
     # extend data\r
     writer.write_uint(1, 1)\r
-    writer.write_text(model.english_name, 20)\r
-    writer.write_text(model.english_comment, 256)\r
+    writer.write_bytes(model.english_name, 20)\r
+    writer.write_bytes(model.english_comment, 256)\r
     for bone in model.bones:\r
-        writer.write_text(bone.english_name, 20)\r
+        writer.write_bytes(bone.english_name, 20)\r
     for skin in model.morphs:\r
         if skin.name==b'base':\r
             continue\r
-        writer.write_text(skin.english_name, 20)\r
+        writer.write_bytes(skin.english_name, 20)\r
     for g in model.bone_group_list:\r
-        writer.write_text(g.english_name, 50)\r
+        writer.write_bytes(g.english_name, 50)\r
     for toon_texture in model.toon_textures:\r
-        writer.write_text(toon_texture, 100)\r
+        writer.write_bytes(toon_texture, 100)\r
     writer.write_rigidbodies(model.rigidbodies)\r
     writer.write_joints(model.joints)\r
     return True\r
index d5665dc..42b15f6 100644 (file)
@@ -81,13 +81,23 @@ class Bone(object):
             layer,\r
             flag\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
 \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 getConnectionFlag(self):\r
         return self.flag & 0x0001\r
 \r
@@ -119,7 +129,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 +137,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,7 +148,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
@@ -146,14 +156,14 @@ 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
             ):\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,14 +171,35 @@ 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.comment=name.__class__() # unicode\r
         self.vertex_count=0\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 __str__(self):\r
         return ("<pmx.Material {name}>".format(\r
             name=self.english_name\r
@@ -188,6 +219,9 @@ class Bdef1(object):
     def __init__(self, index0):\r
         self.index0=index0\r
 \r
+    def __eq__(self, rhs):\r
+        return self.index0==rhs.index0\r
+\r
 \r
 class Bdef2(object):\r
     """bone deform. use two weights\r
@@ -203,6 +237,13 @@ class Bdef2(object):
         self.index1=index1\r
         self.weight0=weight0\r
 \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
+                )\r
+\r
 \r
 class Vertex(object):\r
     """pmx vertex\r
@@ -222,6 +263,15 @@ class Vertex(object):
         self.deform=deform\r
         self.edge_factor=edge_factor\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
 \r
 class Morph(object):\r
     """pmx morph\r
@@ -247,6 +297,15 @@ 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
 \r
 class VerexMorphOffset(object):\r
     """pmx vertex morph offset\r
@@ -263,6 +322,12 @@ 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
 \r
 class DisplaySlot(object):\r
     """pmx display slot\r
@@ -285,30 +350,13 @@ class DisplaySlot(object):
         self.special_flag=special_flag\r
         self.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
-\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
+    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
 \r
 class RigidBodyParam(object):\r
@@ -336,6 +384,15 @@ 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
 \r
 class RigidBody(object):\r
     """pmx rigidbody\r
@@ -356,7 +413,10 @@ class RigidBody(object):
             'bone_index',\r
             'collision_group',\r
             'no_collision_group',\r
-            'shape',\r
+            'shape_type',\r
+            'shape_size',\r
+            'shape_position',\r
+            'shape_rotation',\r
             'param',\r
             'mode',\r
             ]\r
@@ -382,20 +442,28 @@ class RigidBody(object):
         self.bone_index=bone_index\r
         self.collision_group=collision_group\r
         self.no_collision_group=no_collision_group\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.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
+    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
 \r
 class Joint(object):\r
     """pmx joint\r
@@ -457,6 +525,23 @@ class Joint(object):
         self.spring_constant_translation=spring_constant_translation\r
         self.spring_constant_rotation=spring_constant_rotation\r
 \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
 \r
 class Model(object):\r
     """pmx data representation\r
@@ -503,6 +588,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 +600,21 @@ 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
index 40358bb..a95ab21 100644 (file)
@@ -78,7 +78,7 @@ class Reader(pymeshio.common.BinaryReader):
                 name=self.read_text(),\r
                 english_name=self.read_text(),\r
                 diffuse_color=self.read_rgb(),\r
-                diffuse_alpha=self.read_float(),\r
+                alpha=self.read_float(),\r
                 specular_color=self.read_rgb(),\r
                 specular_factor=self.read_float(),\r
                 ambient_color=self.read_rgb(),\r
@@ -86,8 +86,8 @@ class Reader(pymeshio.common.BinaryReader):
                 edge_color=self.read_rgba(),\r
                 edge_size=self.read_float(),\r
                 texture_index=self.read_texture_index(),\r
-                sphia_texture_index=self.read_texture_index(),\r
-                sphia_mode=self.read_uint(1),\r
+                sphere_texture_index=self.read_texture_index(),\r
+                sphere_mode=self.read_uint(1),\r
                 toon_sharing_flag=self.read_uint(1),\r
                 )\r
         if material.toon_sharing_flag==0:\r
@@ -147,6 +147,7 @@ class Reader(pymeshio.common.BinaryReader):
         link_size=self.read_uint(4)\r
         ik.link=[self.read_ik_link() \r
                 for _ in range(link_size)]\r
+        return ik\r
 \r
     def read_ik_link(self):\r
         link=pymeshio.pmx.IkLink(\r
@@ -230,6 +231,7 @@ class Reader(pymeshio.common.BinaryReader):
             else:\r
                 raise pymeshio.common.ParseException(\r
                         "unknown display_type: {0}".format(display_type))\r
+        return display_slot\r
 \r
     def read_rigidbody(self):\r
         return pymeshio.pmx.RigidBody(\r
diff --git a/pymeshio/pmx/writer.py b/pymeshio/pmx/writer.py
new file mode 100644 (file)
index 0000000..073a665
--- /dev/null
@@ -0,0 +1,326 @@
+# coding: utf-8\r
+import io\r
+import struct\r
+from .. import common\r
+from .. import pmx\r
+\r
+class Writer(common.BinaryWriter):\r
+    """pmx writer\r
+    """\r
+    def __init__(self, ios,\r
+            text_encoding, extended_uv,\r
+            vertex_index_size, texture_index_size, material_index_size,\r
+            bone_index_size, morph_index_size, rigidbody_index_size):\r
+        super(Writer, self).__init__(ios)\r
+        if text_encoding==0:\r
+            def write_text(unicode):\r
+               utf16=unicode.encode('utf16') \r
+               self.write_uint(len(utf16), 4)\r
+               self.write_bytes(utf16)\r
+            self.write_text=write_text\r
+        elif text_encoding==1:\r
+            def write_text(unicode):\r
+               utf8=unicode.encode('utf8') \r
+               self.write_uint(len(utf8), 4)\r
+               self.write_bytes(utf8)\r
+            self.write_text=write_text\r
+        else:\r
+            raise WriteError(\r
+                    "invalid text_encoding: {0}".format(text_encoding))\r
+\r
+        self.write_vertex_index=lambda index: self.write_uint(index, vertex_index_size)\r
+        self.write_texture_index=lambda index: self.write_uint(index, texture_index_size)\r
+        self.write_material_index=lambda index: self.write_uint(index, material_index_size)\r
+        self.write_bone_index=lambda index: self.write_uint(index, bone_index_size)\r
+        self.write_morph_index=lambda index: self.write_uint(index, morph_index_size)\r
+        self.write_rigidbody_index=lambda index: self.write_uint(index, rigidbody_index_size)\r
+\r
+    def write_vertices(self, vertices):\r
+        self.write_uint(len(vertices), 4)\r
+        for v in vertices:\r
+            self.write_vector3(v.position)\r
+            self.write_vector3(v.normal)\r
+            self.write_vector2(v.uv)\r
+            self.write_deform(v.deform)\r
+            self.write_float(v.edge_factor)\r
+\r
+    def write_deform(self, deform):\r
+        if isinstance(deform, pmx.Bdef1):\r
+            self.write_uint(0, 1)\r
+            self.write_bone_index(deform.index0)\r
+        elif isinstance(deform, pmx.Bdef2):\r
+            self.write_uint(1, 1)\r
+            self.write_bone_index(deform.index0)\r
+            self.write_bone_index(deform.index1)\r
+            self.write_float(deform.weight0)\r
+        elif isinstance(deform, pmx.Bdef4):\r
+            # todo\r
+            raise pymeshio.common.WriteException(\r
+                    "not implemented Bdef4")\r
+        else:\r
+            raise pymeshio.common.WriteException(\r
+                    "unknown deform type: {0}".format(deform.type))\r
+\r
+    def write_indices(self, indices):\r
+        self.write_uint(len(indices), 4)\r
+        for i in indices:\r
+            self.write_vertex_index(i)\r
+\r
+    def write_textures(self, textures):\r
+        self.write_uint(len(textures), 4)\r
+        for t in textures:\r
+            self.write_text(t)\r
+\r
+    def write_materials(self, materials):\r
+        self.write_uint(len(materials), 4)\r
+        for m in materials:\r
+            self.write_text(m.name)\r
+            self.write_text(m.english_name)\r
+            self.write_rgb(m.diffuse_color)\r
+            self.write_float(m.alpha)\r
+            self.write_rgb(m.specular_color)\r
+            self.write_float(m.specular_factor)\r
+            self.write_rgb(m.ambient_color)\r
+            self.write_uint(m.flag, 1)\r
+            self.write_rgba(m.edge_color)\r
+            self.write_float(m.edge_size)\r
+            self.write_texture_index(m.texture_index)\r
+            self.write_texture_index(m.sphere_texture_index)\r
+            self.write_uint(m.sphere_mode, 1)\r
+            self.write_uint(m.toon_sharing_flag, 1)\r
+            if m.toon_sharing_flag==0:\r
+                self.write_texture_index(m.toon_texture_index)\r
+            elif m.toon_sharing_flag==1:\r
+                self.write_uint(m.toon_texture_index, 1)\r
+            else:\r
+                raise common.WriteException(\r
+                        "unknown toon_sharing_flag {0}".format(m.toon_sharing_flag))\r
+            self.write_text(m.comment)\r
+            self.write_uint(m.vertex_count, 4)\r
+\r
+    def write_bones(self, bones):\r
+        self.write_uint(len(bones), 4)\r
+        for bone in bones:\r
+            self.write_text(bone.name)\r
+            self.write_text(bone.english_name)\r
+            self.write_vector3(bone.position)\r
+            self.write_bone_index(bone.parent_index)\r
+            self.write_uint(bone.layer, 4)\r
+            self.write_uint(bone.flag, 2)\r
+            if bone.getConnectionFlag()==0:\r
+                self.write_vector3(bone.tail_positoin)\r
+            elif bone.getConnectionFlag()==1:\r
+                self.write_bone_index(bone.tail_index)\r
+            else:\r
+                raise pymeshio.common.WriteException(\r
+                        "unknown bone conenction flag: {0}".format(\r
+                            bone.getConnectionFlag()))\r
+\r
+            if bone.getRotationFlag()==1 or bone.getTranslationFlag()==1:\r
+                self.write_bone_index(bone.effect_index)\r
+                self.write_float(bone.effect_factor)\r
+\r
+            if bone.getFixedAxisFlag()==1:\r
+                self.write_vector3(bone.fixed_axis)\r
+\r
+            if bone.getLocalCoordinateFlag()==1:\r
+                self.write_vector3(bone.local_x_vector)\r
+                self.write_vector3(bone.local_z_vector)\r
+\r
+            if bone.getExternalParentDeformFlag()==1:\r
+                self.write_uint(bone.external_key, 4)\r
+\r
+            if bone.getIkFlag()==1:\r
+                self.write_ik(bone.ik)\r
+\r
+    def write_ik(self, ik):\r
+        self.write_bone_index(ik.target_index)\r
+        self.write_uint(ik.loop, 4)\r
+        self.write_float(ik.limit_radian)\r
+        self.write_uint(len(ik.link), 4)\r
+        for l in ik.link:\r
+            self.write_ik_link(l)\r
+\r
+    def write_ik_link(self, link):\r
+        self.write_bone_index(link.bone_index)\r
+        self.write_uint(link.limit_angle, 1)\r
+        if link.limit_angle==0:\r
+            pass\r
+        elif link.limit_angle==1:\r
+            self.write_vector3(link.limit_min)\r
+            self.write_vector3(link.limit_max)\r
+        else:\r
+            raise pymeshio.common.WriteException(\r
+                    "invalid ik link limit_angle: {0}".format(\r
+                        link.limit_angle))\r
\r
+    def write_morph(self, morphs):\r
+        self.write_uint(len(morphs), 4)\r
+        for m in morphs:\r
+            self.write_text(m.name)\r
+            self.write_text(m.english_name)\r
+            self.write_uint(m.panel, 1)\r
+            self.write_uint(m.morph_type, 1)\r
+            if m.morph_type==0:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented GroupMorph")\r
+            elif m.morph_type==1:\r
+                self.write_uint(len(m.offsets), 4)\r
+                for o in m.offsets:\r
+                    self.write_vertex_index(o.vertex_index)\r
+                    self.write_vector3(o.position_offset)\r
+            elif m.morph_type==2:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented BoneMorph")\r
+            elif m.morph_type==3:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented UvMorph")\r
+            elif m.morph_type==4:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented extended UvMorph1")\r
+            elif m.morph_type==5:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented extended UvMorph2")\r
+            elif m.morph_type==6:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented extended UvMorph3")\r
+            elif m.morph_type==7:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented extended UvMorph4")\r
+            elif m.morph_type==8:\r
+                # todo\r
+                raise pymeshio.common.WriteException(\r
+                        "not implemented extended MaterialMorph")\r
+            else:\r
+                raise pymeshio.common.WriteException(\r
+                        "unknown morph type: {0}".format(m.morph_type))\r
+\r
+    def write_display_slots(self, display_slots):\r
+        self.write_uint(len(display_slots), 4)\r
+        for s in display_slots:\r
+            self.write_text(s.name)\r
+            self.write_text(s.english_name)\r
+            self.write_uint(s.special_flag, 1)\r
+            self.write_uint(len(s.refrences), 4)\r
+            for r in s.refrences:\r
+                self.write_uint(r[0], 1)\r
+                if r[0]==0:\r
+                    self.write_bone_index(r[1])\r
+                elif r[0]==1:\r
+                    self.write_morph_index(r[1])\r
+                else:\r
+                    raise pymeshio.common.WriteException(\r
+                            "unknown display_type: {0}".format(r[0]))\r
+\r
+    def write_rigidbodies(self, rigidbodies):\r
+        self.write_uint(len(rigidbodies), 4)\r
+        for rb in rigidbodies:\r
+            self.write_text(rb.name)\r
+            self.write_text(rb.english_name)\r
+            self.write_bone_index(rb.bone_index)\r
+            self.write_uint(rb.collision_group, 1)\r
+            self.write_uint(rb.no_collision_group, 2)\r
+            self.write_uint(rb.shape_type, 1)\r
+            self.write_vector3(rb.shape_size)\r
+            self.write_vector3(rb.shape_position)\r
+            self.write_vector3(rb.shape_rotation)\r
+            self.write_float(rb.param.mass)\r
+            self.write_float(rb.param.linear_damping)\r
+            self.write_float(rb.param.angular_damping)\r
+            self.write_float(rb.param.restitution)\r
+            self.write_float(rb.param.friction)\r
+            self.write_uint(rb.mode, 1)\r
+\r
+    def write_joints(self, joints):\r
+        self.write_uint(len(joints), 4)\r
+        for j in joints:\r
+            self.write_text(j.name)\r
+            self.write_text(j.english_name)\r
+            self.write_uint(j.joint_type, 1)\r
+            self.write_rigidbody_index(j.rigidbody_index_a)\r
+            self.write_rigidbody_index(j.rigidbody_index_b)\r
+            self.write_vector3(j.position)\r
+            self.write_vector3(j.rotation)\r
+            self.write_vector3(j.translation_limit_min)\r
+            self.write_vector3(j.translation_limit_max)\r
+            self.write_vector3(j.rotation_limit_min)\r
+            self.write_vector3(j.rotation_limit_max)\r
+            self.write_vector3(j.spring_constant_translation)\r
+            self.write_vector3(j.spring_constant_rotation)\r
+\r
+\r
+def write(ios, model, text_encoding=1):\r
+    """pmx\8f\91\82«\8d\9e\82Ý\r
+    """\r
+    assert(isinstance(ios, io.IOBase))\r
+    assert(isinstance(model, pmx.Model))\r
+    writer=common.BinaryWriter(ios)\r
+    # header\r
+    writer.write_bytes(b"PMX ")\r
+    writer.write_float(model.version)\r
+\r
+    # flags\r
+    writer.write_uint(8, 1)\r
+    # textencoding\r
+    writer.write_uint(text_encoding, 1)\r
+    # extend uv\r
+    writer.write_uint(0, 1)\r
+    def get_array_size(size):\r
+        if size<128:\r
+            return 1\r
+        elif size<32768:\r
+            return 2\r
+        elif size<2147483647:\r
+            return 4\r
+        else:\r
+            raise common.WriteError(\r
+                    "invalid array_size: {0}".format(size))\r
+    # vertex_index_size\r
+    vertex_index_size=get_array_size(len(model.vertices))\r
+    writer.write_uint(vertex_index_size, 1)\r
+    # texture_index_size\r
+    texture_index_size=get_array_size(len(model.textures))\r
+    writer.write_uint(texture_index_size, 1)\r
+    # material_index_size\r
+    material_index_size=get_array_size(len(model.materials))\r
+    writer.write_uint(material_index_size, 1)\r
+    # bone_index_size\r
+    bone_index_size=get_array_size(len(model.bones))\r
+    writer.write_uint(bone_index_size, 1)\r
+    # morph_index_size\r
+    morph_index_size=get_array_size(len(model.morphs))\r
+    writer.write_uint(morph_index_size, 1)\r
+    # rigidbody_index_size\r
+    rigidbody_index_size=get_array_size(len(model.rigidbodies))\r
+    writer.write_uint(rigidbody_index_size, 1)\r
+\r
+    writer=Writer(writer.ios, \r
+            text_encoding, 0,\r
+            vertex_index_size, texture_index_size, material_index_size,\r
+            bone_index_size, morph_index_size, rigidbody_index_size)\r
\r
+    # model info\r
+    writer.write_text(model.name)\r
+    writer.write_text(model.english_name)\r
+    writer.write_text(model.comment)\r
+    writer.write_text(model.english_comment)\r
+\r
+    # model data\r
+    writer.write_vertices(model.vertices)\r
+    writer.write_indices(model.indices)\r
+    writer.write_textures(model.textures)\r
+    writer.write_materials(model.materials)\r
+    writer.write_bones(model.bones)\r
+    writer.write_morph(model.morphs)\r
+    writer.write_display_slots(model.display_slots)\r
+    writer.write_rigidbodies(model.rigidbodies)\r
+    writer.write_joints(model.joints)\r
+    return True\r
+\r
index 1e89b0d..e9185ee 100644 (file)
@@ -1,7 +1,9 @@
 # coding: utf-8\r
 import unittest\r
+import io\r
 import pymeshio.pmd\r
 import pymeshio.pmx.reader\r
+import pymeshio.pmx.writer\r
 \r
 \r
 PMX_FILE=pymeshio.unicode('resources/初音ミクVer2.pmx')\r
@@ -44,3 +46,14 @@ class TestPmx(unittest.TestCase):
         self.assertEqual(45,  len(model.rigidbodies))\r
         self.assertEqual(27,  len(model.joints))\r
 \r
+    def test_write(self):\r
+        # read source file\r
+        buf=pymeshio.common.readall(PMX_FILE)\r
+        # read and write to out\r
+        model=pymeshio.pmx.reader.read(io.BytesIO(buf))\r
+        out=io.BytesIO()\r
+        pymeshio.pmx.writer.write(out, model)\r
+        # read out buffer again\r
+        model2=pymeshio.pmx.reader.read(io.BytesIO(out.getvalue()))\r
+        self.assertEqual(model, model2)\r
+\r