OSDN Git Service

9183c0d9ee2f5ff85ffb03ce4dd824598ee0cfc6
[meshio/pymeshio.git] / pymeshio / pmd / reader.py
1 #coding: utf-8\r
2 """\r
3 pmd reader\r
4 """\r
5 import io\r
6 from .. import common\r
7 from .. import pmd\r
8 \r
9 \r
10 class Reader(common.BinaryReader):\r
11     """pmx reader\r
12     """\r
13     def __init__(self, ios, version):\r
14         super(Reader, self).__init__(ios)\r
15         self.version=version\r
16 \r
17     def read_text(self, size):\r
18         """read cp932 text\r
19         """\r
20         src=self.unpack("%ds" % size, size)\r
21         assert(type(src)==bytes)\r
22         pos = src.find(b"\x00")\r
23         if pos==-1:\r
24             return src\r
25         else:\r
26             return src[:pos]\r
27 \r
28     def read_vertex(self):\r
29         return pmd.Vertex(\r
30                 self.read_vector3(),\r
31                 self.read_vector3(),\r
32                 self.read_vector2(),\r
33                 self.read_uint(2),\r
34                 self.read_uint(2),\r
35                 self.read_uint(1),\r
36                 self.read_uint(1))\r
37 \r
38     def read_material(self):\r
39         return pmd.Material(\r
40                 diffuse_color=self.read_rgb(),\r
41                 alpha=self.read_float(),\r
42                 specular_factor=self.read_float(),\r
43                 specular_color=self.read_rgb(),\r
44                 ambient_color=self.read_rgb(),\r
45                 toon_index=self.read_uint(1),\r
46                 edge_flag=self.read_uint(1),\r
47                 vertex_count=self.read_uint(4),\r
48                 texture_file=self.read_text(20)\r
49                 )\r
50 \r
51     def read_bone(self):\r
52         name=self.read_text(20)\r
53         parent_index=self.read_uint(2)\r
54         tail_index=self.read_uint(2)\r
55         bone=pmd.createBone(name, self.read_uint(1))\r
56         bone.parent_index=parent_index\r
57         bone.tail_index=tail_index\r
58         bone.ik_index = self.read_uint(2)\r
59         bone.pos = self.read_vector3()\r
60         return bone\r
61 \r
62     def read_ik(self):\r
63         ik=pmd.IK(self.read_uint(2), self.read_uint(2))\r
64         ik.length = self.read_uint(1)\r
65         ik.iterations = self.read_uint(2)\r
66         ik.weight = self.read_float()\r
67         ik.children=[self.read_uint(2) for _ in range(ik.length)]\r
68         return ik\r
69 \r
70     def read_morph(self):\r
71         morph=pmd.Morph(self.read_text(20))\r
72         morph_size = self.read_uint(4)\r
73         morph.type = self.read_uint(1)\r
74         for j in range(morph_size):\r
75             morph.indices.append(self.read_uint(4))\r
76             morph.pos_list.append(self.read_vector3())\r
77         return morph\r
78 \r
79     def read_rigidbody(self):\r
80         return pmd.RigidBody(\r
81                 name=self.read_text(20), \r
82                 bone_index=self.read_uint(2),\r
83                 collision_group=self.read_uint(1),\r
84                 no_collision_group=self.read_uint(2),\r
85                 shape_type=self.read_uint(1),\r
86                 shape_size=self.read_vector3(),\r
87                 shape_position=self.read_vector3(),\r
88                 shape_rotation=self.read_vector3(),\r
89                 mass=self.read_float(),\r
90                 linear_damping=self.read_float(),\r
91                 angular_damping=self.read_float(),\r
92                 restitution=self.read_float(),\r
93                 friction=self.read_float(),\r
94                 mode=self.read_uint(1)\r
95                 )\r
96 \r
97     def read_joint(self):\r
98         return pmd.Joint(\r
99                 name=self.read_text(20),\r
100                 rigidbody_index_a=self.read_uint(4),\r
101                 rigidbody_index_b=self.read_uint(4),\r
102                 position=self.read_vector3(),\r
103                 rotation=self.read_vector3(),\r
104                 translation_limit_min=self.read_vector3(),\r
105                 translation_limit_max=self.read_vector3(),\r
106                 rotation_limit_min=self.read_vector3(),\r
107                 rotation_limit_max=self.read_vector3(),\r
108                 spring_constant_translation=self.read_vector3(),\r
109                 spring_constant_rotation=self.read_vector3())\r
110 \r
111 \r
112 \r
113 def __read(reader, model):\r
114     # model info\r
115     model.name=reader.read_text(20)\r
116     model.comment=reader.read_text(256) \r
117 \r
118     # model data\r
119     model.vertices=[reader.read_vertex()\r
120             for _ in range(reader.read_uint(4))]\r
121     model.indices=[reader.read_uint(2)\r
122             for _ in range(reader.read_uint(4))]\r
123     model.materials=[reader.read_material()\r
124             for _ in range(reader.read_uint(4))]\r
125     model.bones=[reader.read_bone()\r
126             for _ in range(reader.read_uint(2))]\r
127     model.ik_list=[reader.read_ik()\r
128             for _ in range(reader.read_uint(2))]\r
129     model.morphs=[reader.read_morph()\r
130             for _ in range(reader.read_uint(2))]\r
131     model.morph_indices=[reader.read_uint(2)\r
132             for _ in range(reader.read_uint(1))]\r
133     model.bone_group_list=[pmd.BoneGroup(reader.read_text(50))\r
134             for _ in range(reader.read_uint(1))]\r
135     model.bone_display_list=[(reader.read_uint(2), reader.read_uint(1))\r
136             for _i in range(reader.read_uint(4))]\r
137 \r
138     if reader.is_end():\r
139         # EOF\r
140         return True\r
141 \r
142     ############################################################\r
143     # extend1: english name\r
144     ############################################################\r
145     if reader.read_uint(1)==0:\r
146         print("no extend flag")\r
147         return True\r
148     model.english_name=reader.read_text(20)\r
149     model.english_comment=reader.read_text(256)\r
150     for bone in model.bones:\r
151         bone.english_name=reader.read_text(20)\r
152     for morph in model.morphs:\r
153         if morph.name==b'base':\r
154             continue\r
155         morph.english_name=reader.read_text(20)\r
156     for g in model.bone_group_list:\r
157         g.english_name=reader.read_text(50)\r
158 \r
159 \r
160     ############################################################\r
161     # extend2: toon_textures\r
162     ############################################################\r
163     if reader.is_end():\r
164         # EOF\r
165         return True\r
166     model.toon_textures=[reader.read_text(100)\r
167             for _ in range(10)]\r
168 \r
169     ############################################################\r
170     # extend2: rigidbodies and joints\r
171     ############################################################\r
172     if reader.is_end():\r
173         # EOF\r
174         return True\r
175     model.rigidbodies=[reader.read_rigidbody()\r
176             for _ in range(reader.read_uint(4))]\r
177     model.joints=[reader.read_joint()\r
178             for _ in range(reader.read_uint(4))]\r
179 \r
180     return True\r
181 \r
182 \r
183 def read_from_file(path):\r
184     return read(io.BytesIO(common.readall(path)))\r
185 \r
186 \r
187 def read(ios):\r
188     assert(isinstance(ios, io.IOBase))\r
189     reader=common.BinaryReader(ios)\r
190 \r
191     # header\r
192     signature=reader.unpack("3s", 3)\r
193     if signature!=b"Pmd":\r
194         raise common.ParseException(\r
195                 "invalid signature: {0}".format(signature))\r
196     version=reader.read_float()\r
197 \r
198     model=pmd.Model(version)\r
199     reader=Reader(reader.ios, version)\r
200     if(__read(reader, model)):\r
201         # check eof\r
202         if not reader.is_end():\r
203             #print("can not reach eof.")\r
204             pass\r
205 \r
206         # build bone tree\r
207         for i, child in enumerate(model.bones):\r
208             if child.parent_index==0xFFFF:\r
209                 # no parent\r
210                 model.no_parent_bones.append(child)\r
211                 child.parent=None\r
212             else:\r
213                 # has parent\r
214                 parent=model.bones[child.parent_index]\r
215                 child.parent=parent\r
216                 parent.children.append(child)\r
217             # 後位置\r
218             if child.hasChild():\r
219                 child.tail=model.bones[child.tail_index].pos\r
220 \r
221         return model\r
222 \r
223 \r
224 \r