OSDN Git Service

2d6a89a5fba66107520986742c63c582768f0725
[meshio/pymeshio.git] / pymeshio / pmx / writer.py
1 # coding: utf-8\r
2 """\r
3 pmx writer\r
4 """\r
5 import io\r
6 import struct\r
7 from .. import common\r
8 from .. import pmx\r
9 \r
10 class Writer(common.BinaryWriter):\r
11     """pmx writer\r
12     """\r
13     def __init__(self, ios,\r
14             text_encoding, extended_uv,\r
15             vertex_index_size, texture_index_size, material_index_size,\r
16             bone_index_size, morph_index_size, rigidbody_index_size):\r
17         super(Writer, self).__init__(ios)\r
18         if text_encoding==0:\r
19             def write_text(unicode):\r
20                utf16=unicode.encode('utf16') \r
21                self.write_int(len(utf16), 4)\r
22                self.write_bytes(utf16)\r
23             self.write_text=write_text\r
24         elif text_encoding==1:\r
25             def write_text(unicode):\r
26                utf8=unicode.encode('utf8') \r
27                self.write_int(len(utf8), 4)\r
28                self.write_bytes(utf8)\r
29             self.write_text=write_text\r
30         else:\r
31             raise WriteError(\r
32                     "invalid text_encoding: {0}".format(text_encoding))\r
33 \r
34         self.write_vertex_index=lambda index: self.write_int(index, vertex_index_size)\r
35         self.write_texture_index=lambda index: self.write_int(index, texture_index_size)\r
36         self.write_material_index=lambda index: self.write_int(index, material_index_size)\r
37         self.write_bone_index=lambda index: self.write_int(index, bone_index_size)\r
38         self.write_morph_index=lambda index: self.write_int(index, morph_index_size)\r
39         self.write_rigidbody_index=lambda index: self.write_int(index, rigidbody_index_size)\r
40 \r
41     def write_vertices(self, vertices):\r
42         self.write_int(len(vertices), 4)\r
43         for v in vertices:\r
44             self.write_vector3(v.position)\r
45             self.write_vector3(v.normal)\r
46             self.write_vector2(v.uv)\r
47             self.write_deform(v.deform)\r
48             self.write_float(v.edge_factor)\r
49 \r
50     def write_deform(self, deform):\r
51         if isinstance(deform, pmx.Bdef1):\r
52             self.write_int(0, 1)\r
53             self.write_bone_index(deform.index0)\r
54         elif isinstance(deform, pmx.Bdef2):\r
55             self.write_int(1, 1)\r
56             self.write_bone_index(deform.index0)\r
57             self.write_bone_index(deform.index1)\r
58             self.write_float(deform.weight0)\r
59         elif isinstance(deform, pmx.Bdef4):\r
60             # todo\r
61             raise pymeshio.common.WriteException(\r
62                     "not implemented Bdef4")\r
63         else:\r
64             raise pymeshio.common.WriteException(\r
65                     "unknown deform type: {0}".format(deform.type))\r
66 \r
67     def write_indices(self, indices):\r
68         self.write_int(len(indices), 4)\r
69         for i in indices:\r
70             self.write_vertex_index(i)\r
71 \r
72     def write_textures(self, textures):\r
73         self.write_int(len(textures), 4)\r
74         for t in textures:\r
75             self.write_text(t)\r
76 \r
77     def write_materials(self, materials):\r
78         self.write_int(len(materials), 4)\r
79         for m in materials:\r
80             self.write_text(m.name)\r
81             self.write_text(m.english_name)\r
82             self.write_rgb(m.diffuse_color)\r
83             self.write_float(m.alpha)\r
84             self.write_rgb(m.specular_color)\r
85             self.write_float(m.specular_factor)\r
86             self.write_rgb(m.ambient_color)\r
87             self.write_int(m.flag, 1)\r
88             self.write_rgba(m.edge_color)\r
89             self.write_float(m.edge_size)\r
90             self.write_texture_index(m.texture_index)\r
91             self.write_texture_index(m.sphere_texture_index)\r
92             self.write_int(m.sphere_mode, 1)\r
93             self.write_int(m.toon_sharing_flag, 1)\r
94             if m.toon_sharing_flag==0:\r
95                 self.write_texture_index(m.toon_texture_index)\r
96             elif m.toon_sharing_flag==1:\r
97                 self.write_int(m.toon_texture_index, 1)\r
98             else:\r
99                 raise common.WriteException(\r
100                         "unknown toon_sharing_flag {0}".format(m.toon_sharing_flag))\r
101             self.write_text(m.comment)\r
102             self.write_int(m.vertex_count, 4)\r
103 \r
104     def write_bones(self, bones):\r
105         self.write_int(len(bones), 4)\r
106         for bone in bones:\r
107             self.write_text(bone.name)\r
108             self.write_text(bone.english_name)\r
109             self.write_vector3(bone.position)\r
110             self.write_bone_index(bone.parent_index)\r
111             self.write_int(bone.layer, 4)\r
112             self.write_int(bone.flag, 2)\r
113             if bone.getConnectionFlag()==0:\r
114                 self.write_vector3(bone.tail_position)\r
115             elif bone.getConnectionFlag()==1:\r
116                 self.write_bone_index(bone.tail_index)\r
117             else:\r
118                 raise pymeshio.common.WriteException(\r
119                         "unknown bone conenction flag: {0}".format(\r
120                             bone.getConnectionFlag()))\r
121 \r
122             if bone.getRotationFlag()==1 or bone.getTranslationFlag()==1:\r
123                 self.write_bone_index(bone.effect_index)\r
124                 self.write_float(bone.effect_factor)\r
125 \r
126             if bone.getFixedAxisFlag()==1:\r
127                 self.write_vector3(bone.fixed_axis)\r
128 \r
129             if bone.getLocalCoordinateFlag()==1:\r
130                 self.write_vector3(bone.local_x_vector)\r
131                 self.write_vector3(bone.local_z_vector)\r
132 \r
133             if bone.getExternalParentDeformFlag()==1:\r
134                 self.write_int(bone.external_key, 4)\r
135 \r
136             if bone.getIkFlag()==1:\r
137                 self.write_ik(bone.ik)\r
138 \r
139     def write_ik(self, ik):\r
140         self.write_bone_index(ik.target_index)\r
141         self.write_int(ik.loop, 4)\r
142         self.write_float(ik.limit_radian)\r
143         self.write_int(len(ik.link), 4)\r
144         for l in ik.link:\r
145             self.write_ik_link(l)\r
146 \r
147     def write_ik_link(self, link):\r
148         self.write_bone_index(link.bone_index)\r
149         self.write_int(link.limit_angle, 1)\r
150         if link.limit_angle==0:\r
151             pass\r
152         elif link.limit_angle==1:\r
153             self.write_vector3(link.limit_min)\r
154             self.write_vector3(link.limit_max)\r
155         else:\r
156             raise pymeshio.common.WriteException(\r
157                     "invalid ik link limit_angle: {0}".format(\r
158                         link.limit_angle))\r
159  \r
160     def write_morph(self, morphs):\r
161         self.write_int(len(morphs), 4)\r
162         for m in morphs:\r
163             self.write_text(m.name)\r
164             self.write_text(m.english_name)\r
165             self.write_int(m.panel, 1)\r
166             self.write_int(m.morph_type, 1)\r
167             if m.morph_type==0:\r
168                 # todo\r
169                 raise pymeshio.common.WriteException(\r
170                         "not implemented GroupMorph")\r
171             elif m.morph_type==1:\r
172                 self.write_int(len(m.offsets), 4)\r
173                 for o in m.offsets:\r
174                     self.write_vertex_index(o.vertex_index)\r
175                     self.write_vector3(o.position_offset)\r
176             elif m.morph_type==2:\r
177                 # todo\r
178                 raise pymeshio.common.WriteException(\r
179                         "not implemented BoneMorph")\r
180             elif m.morph_type==3:\r
181                 # todo\r
182                 raise pymeshio.common.WriteException(\r
183                         "not implemented UvMorph")\r
184             elif m.morph_type==4:\r
185                 # todo\r
186                 raise pymeshio.common.WriteException(\r
187                         "not implemented extended UvMorph1")\r
188             elif m.morph_type==5:\r
189                 # todo\r
190                 raise pymeshio.common.WriteException(\r
191                         "not implemented extended UvMorph2")\r
192             elif m.morph_type==6:\r
193                 # todo\r
194                 raise pymeshio.common.WriteException(\r
195                         "not implemented extended UvMorph3")\r
196             elif m.morph_type==7:\r
197                 # todo\r
198                 raise pymeshio.common.WriteException(\r
199                         "not implemented extended UvMorph4")\r
200             elif m.morph_type==8:\r
201                 # todo\r
202                 raise pymeshio.common.WriteException(\r
203                         "not implemented extended MaterialMorph")\r
204             else:\r
205                 raise pymeshio.common.WriteException(\r
206                         "unknown morph type: {0}".format(m.morph_type))\r
207 \r
208     def write_display_slots(self, display_slots):\r
209         self.write_int(len(display_slots), 4)\r
210         for s in display_slots:\r
211             self.write_text(s.name)\r
212             self.write_text(s.english_name)\r
213             self.write_int(s.special_flag, 1)\r
214             self.write_int(len(s.refrences), 4)\r
215             for r in s.refrences:\r
216                 self.write_int(r[0], 1)\r
217                 if r[0]==0:\r
218                     self.write_bone_index(r[1])\r
219                 elif r[0]==1:\r
220                     self.write_morph_index(r[1])\r
221                 else:\r
222                     raise pymeshio.common.WriteException(\r
223                             "unknown display_type: {0}".format(r[0]))\r
224 \r
225     def write_rigidbodies(self, rigidbodies):\r
226         self.write_int(len(rigidbodies), 4)\r
227         for rb in rigidbodies:\r
228             self.write_text(rb.name)\r
229             self.write_text(rb.english_name)\r
230             self.write_bone_index(rb.bone_index)\r
231             self.write_int(rb.collision_group, 1)\r
232             self.write_int(rb.no_collision_group, 2)\r
233             self.write_int(rb.shape_type, 1)\r
234             self.write_vector3(rb.shape_size)\r
235             self.write_vector3(rb.shape_position)\r
236             self.write_vector3(rb.shape_rotation)\r
237             self.write_float(rb.param.mass)\r
238             self.write_float(rb.param.linear_damping)\r
239             self.write_float(rb.param.angular_damping)\r
240             self.write_float(rb.param.restitution)\r
241             self.write_float(rb.param.friction)\r
242             self.write_int(rb.mode, 1)\r
243 \r
244     def write_joints(self, joints):\r
245         self.write_int(len(joints), 4)\r
246         for j in joints:\r
247             self.write_text(j.name)\r
248             self.write_text(j.english_name)\r
249             self.write_int(j.joint_type, 1)\r
250             self.write_rigidbody_index(j.rigidbody_index_a)\r
251             self.write_rigidbody_index(j.rigidbody_index_b)\r
252             self.write_vector3(j.position)\r
253             self.write_vector3(j.rotation)\r
254             self.write_vector3(j.translation_limit_min)\r
255             self.write_vector3(j.translation_limit_max)\r
256             self.write_vector3(j.rotation_limit_min)\r
257             self.write_vector3(j.rotation_limit_max)\r
258             self.write_vector3(j.spring_constant_translation)\r
259             self.write_vector3(j.spring_constant_rotation)\r
260 \r
261 \r
262 def write(ios, model, text_encoding=1):\r
263     """\r
264     write model to ios.\r
265 \r
266     :Parameters:\r
267         ios\r
268             output stream (in io.IOBase)\r
269         model\r
270             pmx model\r
271         text_encoding\r
272             text field encoding (0: UTF16, 1:UTF-8).\r
273             0: UTF16 has bug. it write BOM(FFFE).\r
274 \r
275     >>> import pymeshio.pmx.writer\r
276     >>> pymeshio.pmx.writer.write(io.open('out.pmx', 'wb'), pmx_model)\r
277 \r
278     """\r
279     assert(isinstance(ios, io.IOBase))\r
280     assert(isinstance(model, pmx.Model))\r
281     writer=common.BinaryWriter(ios)\r
282     # header\r
283     writer.write_bytes(b"PMX ")\r
284     writer.write_float(model.version)\r
285 \r
286     # flags\r
287     writer.write_int(8, 1)\r
288     # textencoding\r
289     writer.write_int(text_encoding, 1)\r
290     # extend uv\r
291     writer.write_int(0, 1)\r
292     def get_array_size(size):\r
293         if size<128:\r
294             return 1\r
295         elif size<32768:\r
296             return 2\r
297         elif size<2147483647:\r
298             return 4\r
299         else:\r
300             raise common.WriteError(\r
301                     "invalid array_size: {0}".format(size))\r
302     # vertex_index_size\r
303     vertex_index_size=get_array_size(len(model.vertices))\r
304     writer.write_int(vertex_index_size, 1)\r
305     # texture_index_size\r
306     texture_index_size=get_array_size(len(model.textures))\r
307     writer.write_int(texture_index_size, 1)\r
308     # material_index_size\r
309     material_index_size=get_array_size(len(model.materials))\r
310     writer.write_int(material_index_size, 1)\r
311     # bone_index_size\r
312     bone_index_size=get_array_size(len(model.bones))\r
313     writer.write_int(bone_index_size, 1)\r
314     # morph_index_size\r
315     morph_index_size=get_array_size(len(model.morphs))\r
316     writer.write_int(morph_index_size, 1)\r
317     # rigidbody_index_size\r
318     rigidbody_index_size=get_array_size(len(model.rigidbodies))\r
319     writer.write_int(rigidbody_index_size, 1)\r
320 \r
321     writer=Writer(writer.ios, \r
322             text_encoding, 0,\r
323             vertex_index_size, texture_index_size, material_index_size,\r
324             bone_index_size, morph_index_size, rigidbody_index_size)\r
325  \r
326     # model info\r
327     writer.write_text(model.name)\r
328     writer.write_text(model.english_name)\r
329     writer.write_text(model.comment)\r
330     writer.write_text(model.english_comment)\r
331 \r
332     # model data\r
333     writer.write_vertices(model.vertices)\r
334     writer.write_indices(model.indices)\r
335     writer.write_textures(model.textures)\r
336     writer.write_materials(model.materials)\r
337     writer.write_bones(model.bones)\r
338     writer.write_morph(model.morphs)\r
339     writer.write_display_slots(model.display_slots)\r
340     writer.write_rigidbodies(model.rigidbodies)\r
341     writer.write_joints(model.joints)\r
342     return True\r
343 \r