OSDN Git Service

fix mode
[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_int(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_int(2),\r
83                 collision_group=self.read_int(1),\r
84                 no_collision_group=self.read_int(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)==1:\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 \r
176     model.rigidbodies=[reader.read_rigidbody()\r
177             for _ in range(reader.read_uint(4))]\r
178     model.joints=[reader.read_joint()\r
179             for _ in range(reader.read_uint(4))]\r
180 \r
181     return True\r
182 \r
183 \r
184 def read_from_file(path):\r
185     """\r
186     read from file path, then return the pymeshio.pmd.Model.\r
187 \r
188     :Parameters:\r
189       path\r
190         file path\r
191 \r
192     >>> import pymeshio.pmd.reader\r
193     >>> m=pymeshio.pmd.reader.read_from_file('resources/初音ミクVer2.pmd')\r
194     >>> print(m)\r
195     <pmd-2.0 "Miku Hatsune" 12354vertices>\r
196 \r
197     """\r
198     pmd=read(io.BytesIO(common.readall(path)))\r
199     pmd.path=path\r
200     return pmd\r
201 \r
202 \r
203 def read(ios):\r
204     """\r
205     read from ios, then return the pymeshio.pmd.Model.\r
206 \r
207     :Parameters:\r
208       ios\r
209         input stream (in io.IOBase)\r
210 \r
211     >>> import pymeshio.pmd.reader\r
212     >>> m=pymeshio.pmd.reader.read(io.open('resources/初音ミクVer2.pmd', 'rb'))\r
213     >>> print(m)\r
214     <pmd-2.0 "Miku Hatsune" 12354vertices>\r
215 \r
216     """\r
217     assert(isinstance(ios, io.IOBase))\r
218     reader=common.BinaryReader(ios)\r
219 \r
220     # header\r
221     signature=reader.unpack("3s", 3)\r
222     if signature!=b"Pmd":\r
223         raise common.ParseException(\r
224                 "invalid signature: {0}".format(signature))\r
225     version=reader.read_float()\r
226 \r
227     model=pmd.Model(version)\r
228     reader=Reader(reader.ios, version)\r
229     if(__read(reader, model)):\r
230         # check eof\r
231         if not reader.is_end():\r
232             #print("can not reach eof.")\r
233             pass\r
234 \r
235         # build bone tree\r
236         for i, child in enumerate(model.bones):\r
237             child.index=i\r
238             if child.parent_index==0xFFFF:\r
239                 # no parent\r
240                 model.no_parent_bones.append(child)\r
241                 child.parent=None\r
242             else:\r
243                 # has parent\r
244                 parent=model.bones[child.parent_index]\r
245                 child.parent=parent\r
246                 parent.children.append(child)\r
247             # 後位置\r
248             if child.hasChild():\r
249                 child.tail=model.bones[child.tail_index].pos\r
250 \r
251         return model\r
252 \r
253 \r
254 \r