OSDN Git Service

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