OSDN Git Service

refactoring
[meshio/pymeshio.git] / pymeshio / pmx / loader.py
1 # coding: utf-8\r
2 import io\r
3 import pymeshio.common\r
4 import pymeshio.pmx\r
5 \r
6 \r
7 class Loader(pymeshio.common.BinaryLoader):\r
8     """pmx loader\r
9     """\r
10     def __init__(self, io,\r
11             text_encoding,\r
12             extended_uv,\r
13             vertex_index_size,\r
14             texture_index_size,\r
15             material_index_size,\r
16             bone_index_size,\r
17             morph_index_size,\r
18             rigidbody_index_size\r
19             ):\r
20         super(Loader, self).__init__(io)\r
21         self.read_text=self.get_read_text(text_encoding)\r
22         if extended_uv>0:\r
23             raise ParseException("extended uv is not supported", extended_uv)\r
24         self.read_vertex_index=lambda : self.read_uint(vertex_index_size)\r
25         self.read_texture_index=lambda : self.read_uint(texture_index_size)\r
26         self.read_material_index=lambda : self.read_uint(material_index_size)\r
27         self.read_bone_index=lambda : self.read_uint(bone_index_size)\r
28         self.read_morph_index=lambda : self.read_uint(morph_index_size)\r
29         self.read_rigidbody_index=lambda : self.read_uint(rigidbody_index_size)\r
30 \r
31     def __str__(self) -> str:\r
32         return '<pymeshio.pmx.Loader>'\r
33 \r
34     def get_read_text(self, text_encoding) -> "text process function":\r
35         if text_encoding==0:\r
36             def read_text():\r
37                 size=self.read_uint(4)\r
38                 return self.unpack("{0}s".format(size), size).decode("UTF16")\r
39             return read_text\r
40         elif text_encoding==1:\r
41             def read_text():\r
42                 size=self.read_uint(4)\r
43                 return self.unpack("{0}s".format(size), size).decode("UTF8")\r
44             return read_text\r
45         else:\r
46             print("unknown text encoding", text_encoding)\r
47 \r
48     def read_vertex(self):\r
49         return pymeshio.pmx.Vertex(\r
50                 self.read_vector3(), # pos\r
51                 self.read_vector3(), # normal\r
52                 self.read_vector2(), # uv\r
53                 self.read_deform(), # deform(bone weight)\r
54                 self.read_float() # edge factor\r
55                 )\r
56 \r
57     def read_deform(self):\r
58         deform_type=self.read_uint(1)\r
59         if deform_type==0:\r
60             return pymeshio.pmx.Bdef1(self.read_bone_index())\r
61         if deform_type==1:\r
62             return pymeshio.pmx.Bdef2(\r
63                     self.read_bone_index(),\r
64                     self.read_bone_index(),\r
65                     self.read_float()\r
66                     )\r
67         """\r
68         if deform_type==2:\r
69             return pymeshio.pmx.Bdef4(\r
70                     self.read_bone_index(),\r
71                     self.read_bone_index(),\r
72                     self.read_bone_index(),\r
73                     self.read_bone_index(),\r
74                     self.read_float(), self.read_float(),\r
75                     self.read_float(), self.read_float()\r
76                     )\r
77         """\r
78         raise ParseException("unknown deform type: {0}".format(deform_type))\r
79 \r
80     def read_material(self):\r
81         material=pymeshio.pmx.Material(\r
82                 name=self.read_text(),\r
83                 english_name=self.read_text(),\r
84                 diffuse_color=self.read_rgb(),\r
85                 diffuse_alpha=self.read_float(),\r
86                 specular_color=self.read_rgb(),\r
87                 specular_factor=self.read_float(),\r
88                 ambient_color=self.read_rgb(),\r
89                 flag=self.read_uint(1),\r
90                 edge_color=self.read_rgba(),\r
91                 edge_size=self.read_float(),\r
92                 texture_index=self.read_texture_index(),\r
93                 sphia_texture_index=self.read_texture_index(),\r
94                 sphia_mode=self.read_uint(1),\r
95                 toon_sharing_flag=self.read_uint(1),\r
96                 )\r
97         if material.toon_sharing_flag==0:\r
98             material.toon_texture_index=self.read_texture_index()\r
99         elif material.toon_sharing_flag==1:\r
100             material.toon_texture_index=self.read_uint(1)\r
101         else:\r
102             raise ParseException("unknown toon_sharing_flag {0}".format(material.toon_sharing_flag))\r
103         material.comment=self.read_text()\r
104         material.index_count=self.read_uint(4)\r
105         return material\r
106 \r
107     def read_bone(self):\r
108         bone=pymeshio.pmx.Bone(\r
109                 name=self.read_text(),\r
110                 english_name=self.read_text(),\r
111                 position=self.read_vector3(),\r
112                 parent_index=self.read_bone_index(),\r
113                 layer=self.read_uint(4),\r
114                 flag=self.read_uint(2)                \r
115                 )\r
116         if bone.getConnectionFlag()==0:\r
117             bone.tail_positoin=self.read_vector3()\r
118         elif bone.getConnectionFlag()==1:\r
119             bone.tail_index=self.read_bone_index()\r
120         else:\r
121             raise ParseException("unknown bone conenction flag: {0}".format(\r
122                 bone.getConnectionFlag()))\r
123 \r
124         if bone.getRotationFlag()==1 or bone.getTranslationFlag()==1:\r
125             bone.effect_index=self.read_bone_index()\r
126             bone.effect_factor=self.read_float()\r
127 \r
128         if bone.getFixedAxisFlag()==1:\r
129             bone.fixed_axis=self.read_vector3()\r
130 \r
131         if bone.getLocalCoordinateFlag()==1:\r
132             bone.local_x_vector=self.read_vector3()\r
133             bone.local_z_vector=self.read_vector3()\r
134 \r
135         if bone.getExternalParentDeformFlag()==1:\r
136             bone.external_key=self.read_uint(4)\r
137 \r
138         if bone.getIkFlag()==1:\r
139             bone.ik=self.read_ik()\r
140 \r
141         return bone\r
142 \r
143     def read_ik(self):\r
144         ik=pymeshio.pmx.Ik(\r
145                 target_index=self.read_bone_index(),\r
146                 loop=self.read_uint(4),\r
147                 limit_radian=self.read_float())\r
148         link_size=self.read_uint(4)\r
149         ik.link=[self.read_ik_link() for i in range(link_size)]\r
150 \r
151     def read_ik_link(self):\r
152         link=pymeshio.pmx.IkLink(\r
153                 self.read_bone_index(),\r
154                 self.read_uint(1))\r
155         if link.limit_angle==0:\r
156             pass\r
157         elif link.limit_angle==1:\r
158             link.limit_min=self.read_vector3()\r
159             link.limit_max=self.read_vector3()\r
160         else:\r
161             raise ParseException("invalid ik link limit_angle: {0}".format(\r
162                 link.limit_angle))\r
163         return link\r
164 \r
165 \r
166 def load(path: str) -> pymeshio.pmx.Model:\r
167     # general binary loader\r
168     loader=pymeshio.common.BinaryLoader(\r
169             io.BytesIO(\r
170                 pymeshio.common.readall(path)))\r
171 \r
172     # header\r
173     signature=loader.unpack("4s", 4)\r
174     if signature!=b"PMX ":\r
175         raise ParseException("invalid signature", loader.signature)\r
176 \r
177     version=loader.read_float()\r
178     if version!=2.0:\r
179         print("unknown version", version)\r
180     model=pymeshio.pmx.Model(version)\r
181 \r
182     # flags\r
183     flag_bytes=loader.read_uint(1)\r
184     if flag_bytes!=8:\r
185         raise ParseException("invalid flag length", loader.flag_bytes)\r
186     text_encoding=loader.read_uint(1)\r
187     extended_uv=loader.read_uint(1)\r
188     vertex_index_size=loader.read_uint(1)\r
189     texture_index_size=loader.read_uint(1)\r
190     material_index_size=loader.read_uint(1)\r
191     bone_index_size=loader.read_uint(1)\r
192     morph_index_size=loader.read_uint(1)\r
193     rigidbody_index_size=loader.read_uint(1)\r
194     \r
195     # pmx custom loader\r
196     loader=Loader(loader.io,\r
197             text_encoding,\r
198             extended_uv,\r
199             vertex_index_size,\r
200             texture_index_size,\r
201             material_index_size,\r
202             bone_index_size,\r
203             morph_index_size,\r
204             rigidbody_index_size\r
205             )\r
206 \r
207     # model info\r
208     model.name = loader.read_text()\r
209     model.english_name = loader.read_text()\r
210     model.comment = loader.read_text()\r
211     model.english_comment = loader.read_text()\r
212 \r
213     # vertices\r
214     vertex_count=loader.read_uint(4)\r
215     model.vertices=[loader.read_vertex() for i in range(vertex_count)]\r
216 \r
217     # indices\r
218     index_count=loader.read_uint(4)\r
219     model.indices=[loader.read_vertex_index() for i in range(index_count)]\r
220 \r
221     # textures\r
222     texture_count=loader.read_uint(4)\r
223     model.textures=[loader.read_text() for i in range(texture_count)]\r
224 \r
225     # materials\r
226     material_count=loader.read_uint(4)\r
227     model.materials=[loader.read_material() for i in range(material_count)]\r
228 \r
229     # bones\r
230     bone_count=loader.read_uint(4)\r
231     model.bones=[loader.read_bone() for i in range(bone_count)]\r
232 \r
233     return model\r
234 \r