OSDN Git Service

fix export_pmd
[meshio/pymeshio.git] / pymeshio / pmd / __init__.py
1 # coding: utf-8
2 """
3 PMDの読み込み
4 http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
5 """
6 import os
7 import sys
8 import struct
9 import warnings
10 from .. import common
11
12
13 class Vertex(object):
14     """pmd vertex struct.
15
16     Attributes:
17         pos: Vector3
18         normal: Vector3
19         uv: Vector2
20         bone0: bone index
21         bone1: bone index
22         weight0: bone0 influence
23         edge_flag: int flag
24     """
25     __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
26     def __init__(self, pos, normal, uv, 
27             bone0, bone1, weight0, edge_flag):
28         self.pos=pos
29         self.normal=normal
30         self.uv=uv
31         self.bone0=bone0
32         self.bone1=bone1
33         self.weight0=weight0
34         self.edge_flag=edge_flag
35
36     def __str__(self):
37         return "<%s %s %s, (%d, %d, %d)>" % (
38                 str(self.pos), 
39                 str(self.normal), 
40                 str(self.uv), 
41                 self.bone0, self.bone1, self.weight0)
42
43     def __eq__(self, rhs):
44         return (
45                 self.pos==rhs.pos
46                 and self.normal==rhs.normal
47                 and self.uv==rhs.uv
48                 and self.bone0==rhs.bone0
49                 and self.bone1==rhs.bone1
50                 and self.weight0==rhs.weight0
51                 and self.edge_flag==rhs.edge_flag
52                 )
53
54     def __getitem__(self, key):
55         if key==0:
56             return self.pos.x
57         elif key==1:
58             return self.pos.y
59         elif key==2:
60             return self.pos.z
61         else:
62             assert(False)
63
64
65 class Material(object):
66     """pmd material struct.
67
68     Attributes:
69         diffuse_color: RGB
70         alpha: float
71         specular_factor: float
72         specular_color: RGB
73         ambient_color: RGB
74         toon_index: int
75         edge_flag: int
76         vertex_count: indices length
77         texture_file: texture file path
78     """
79     __slots__=[
80             'diffuse_color', 'alpha', 
81             'specular_factor', 'specular_color', 'ambient_color', 
82             'toon_index', 'edge_flag',
83             'vertex_count', 'texture_file', 
84             ]
85     def __init__(self, diffuse_color, alpha,
86             specular_factor, specular_color, ambient_color,
87             toon_index, edge_flag, vertex_count, texture_file):
88         self.diffuse_color=diffuse_color
89         self.alpha=alpha
90         self.specular_factor=specular_factor
91         self.specular_color=specular_color
92         self.ambient_color=ambient_color
93         self.toon_index=toon_index
94         self.edge_flag=edge_flag
95         self.vertex_count=vertex_count
96         self.texture_file=texture_file
97
98     def __str__(self):
99         return "<Material [%f, %f, %f, %f]>" % (
100                 self.diffuse[0], self.diffuse[1], 
101                 self.diffuse[2], self.diffuse[3],
102                 )
103
104     def __eq__(self, rhs):
105         return (
106                 self.diffuse_color==rhs.diffuse_color
107                 and self.alpha==rhs.alpha
108                 and self.specular_factor==rhs.specular_factor
109                 and self.specular_color==rhs.specular_color
110                 and self.ambient_color==rhs.ambient_color
111                 and self.toon_index==rhs.toon_index
112                 and self.edge_flag==rhs.edge_flag
113                 and self.vertex_count==rhs.vertex_count
114                 and self.texture_file==rhs.texture_file
115                 )
116
117
118 class Bone(object):
119     """pmd material struct.
120
121     Attributes:
122         _name: 
123         index:
124         type:
125         ik:
126         pos:
127         _english_name:
128         ik_index:
129         parent_index:
130         tail_index:
131
132         parent:
133         tail:
134         children:
135     """
136     # kinds
137     ROTATE = 0
138     ROTATE_MOVE = 1
139     IK = 2
140     IK_ROTATE_INFL = 4
141     ROTATE_INFL = 5
142     IK_TARGET = 6
143     UNVISIBLE = 7
144     # since v4.0
145     ROLLING=8 # ?
146     TWEAK=9
147     __slots__=['name', 'index', 'type', 'parent', 'ik', 'pos',
148             'children', 'english_name', 'ik_index',
149             'parent_index', 'tail_index', 'tail',
150             ]
151     def __init__(self, name=b'bone', type=0):
152         self.name=name
153         self.index=0
154         self.type=type
155         self.parent_index=0xFFFF
156         self.tail_index=0
157         self.tail=common.Vector3(0, 0, 0)
158         self.parent=None
159         self.ik_index=0xFFFF
160         self.pos=common.Vector3(0, 0, 0)
161         self.children=[]
162         self.english_name=''
163
164     def __eq__(self, rhs):
165         return (
166                 self.name==rhs.name
167                 and self.index==rhs.index
168                 and self.type==rhs.type
169                 and self.parent_index==rhs.parent_index
170                 and self.tail_index==rhs.tail_index
171                 and self.tail==rhs.tail
172                 and self.ik_index==rhs.ik_index
173                 and self.pos==rhs.pos
174                 and self.children==rhs.children
175                 and self.english_name==rhs.english_name
176                 )
177
178     def hasParent(self):
179         return self.parent_index!=0xFFFF
180
181     def hasChild(self):
182         return self.tail_index!=0
183
184     def display(self, indent=[]):
185         if len(indent)>0:
186             prefix=''
187             for i, is_end in enumerate(indent):
188                 if i==len(indent)-1:
189                     break
190                 else:
191                     prefix+='  ' if is_end else ' |'
192             uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
193             print(uni.encode(ENCODING))
194         else:
195             uni='%s(%s)' % (unicode(self), self.english_name)
196             print(uni.encode(ENCODING))
197
198         child_count=len(self.children)
199         for i in range(child_count):
200             child=self.children[i]
201             if i<child_count-1:
202                 child.display(indent+[False])
203             else:
204                 # last
205                 child.display(indent+[True])
206
207 # 0
208 class Bone_Rotate(Bone):
209     __slots__=[]
210     def __init__(self, name):
211         super(Bone_Rotate, self).__init__(name, 0)
212     def __str__(self):
213         return '<ROTATE %s>' % (self.name)
214 # 1
215 class Bone_RotateMove(Bone):
216     __slots__=[]
217     def __init__(self, name):
218         super(Bone_RotateMove, self).__init__(name, 1)
219     def __str__(self):
220         return '<ROTATE_MOVE %s>' % (self.name)
221 # 2
222 class Bone_IK(Bone):
223     __slots__=[]
224     def __init__(self, name):
225         super(Bone_IK, self).__init__(name, 2)
226     def __str__(self):
227         return '<IK %s>' % (self.name)
228 # 4
229 class Bone_IKRotateInfl(Bone):
230     __slots__=[]
231     def __init__(self, name):
232         super(Bone_IKRotateInfl, self).__init__(name, 4)
233     def __str__(self):
234         return '<IK_ROTATE_INFL %s>' % (self.name)
235 # 5
236 class Bone_RotateInfl(Bone):
237     __slots__=[]
238     def __init__(self, name):
239         super(Bone_RotateInfl, self).__init__(name, 5)
240     def __str__(self):
241         return '<ROTATE_INFL %s>' % (self.name)
242 # 6
243 class Bone_IKTarget(Bone):
244     __slots__=[]
245     def __init__(self, name):
246         super(Bone_IKTarget, self).__init__(name, 6)
247     def __str__(self):
248         return '<IK_TARGET %s>' % (self.name)
249 # 7
250 class Bone_Unvisible(Bone):
251     __slots__=[]
252     def __init__(self, name):
253         super(Bone_Unvisible, self).__init__(name, 7)
254     def __str__(self):
255         return '<UNVISIBLE %s>' % (self.name)
256 # 8
257 class Bone_Rolling(Bone):
258     __slots__=[]
259     def __init__(self, name):
260         super(Bone_Rolling, self).__init__(name, 8)
261     def __str__(self):
262         return '<ROLLING %s>' % (self.name)
263 # 9
264 class Bone_Tweak(Bone):
265     __slots__=[]
266     def __init__(self, name):
267         super(Bone_Tweak, self).__init__(name, 9)
268     def __str__(self):
269         return '<TWEAK %s>' % (self.name)
270
271
272 def createBone(name, type):
273     if type==0:
274         return Bone_Rotate(name)
275     elif type==1:
276         return Bone_RotateMove(name)
277     elif type==2:
278         return Bone_IK(name)
279     elif type==3:
280         raise Exception("no used bone type: 3(%s)" % name)
281     elif type==4:
282         return Bone_IKRotateInfl(name)
283     elif type==5:
284         return Bone_RotateInfl(name)
285     elif type==6:
286         return Bone_IKTarget(name)
287     elif type==7:
288         return Bone_Unvisible(name)
289     elif type==8:
290         return Bone_Rolling(name)
291     elif type==9:
292         return Bone_Tweak(name)
293     else:
294         raise Exception("unknown bone type: %d(%s)", type, name)
295
296
297 class IK(object):
298     __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
299     def __init__(self, index=0, target=0):
300         self.index=index
301         self.target=target
302         self.iterations=None
303         self.weight=None
304         self.children=[]
305
306     def __str__(self):
307         return "<IK index: %d, target: %d, iterations: %d, weight: %f, children: %s(%d)>" %(self.index, self.target, self.iterations, self.weight, '-'.join([str(i) for i in self.children]), len(self.children))
308
309     def __eq__(self, rhs):
310         return (
311                 self.index==rhs.index
312                 and self.target==rhs.target
313                 and self.iterations==rhs.iterations
314                 and self.weight==rhs.weight
315                 and self.children==rhs.children
316                 )
317
318
319 class Morph(object):
320     __slots__=['name', 'type', 'indices', 'pos_list', 'english_name',
321             'vertex_count']
322     def __init__(self, name):
323         self.name=name
324         self.type=None
325         self.indices=[]
326         self.pos_list=[]
327         self.english_name=''
328         self.vertex_count=0
329
330     def append(self, index, x, y, z):
331         self.indices.append(index)
332         self.pos_list.append(common.Vector3(x, y, z))
333
334     def __str__(self):
335         return '<Skin name: "%s", type: %d, vertex: %d>' % (
336             self.name, self.type, len(self.indices))
337
338     def __eq__(self, rhs):
339         return (
340                 self.name==rhs.name
341                 and self.type==rhs.type
342                 and self.indices==rhs.indices
343                 and self.pos_list==rhs.pos_list
344                 and self.english_name==rhs.english_name
345                 and self.vertex_count==rhs.vertex_count
346                 )
347
348
349 class BoneGroup(object):
350     __slots__=['name', 'english_name']
351     def __init__(self, name=b'group', english_name=b'center'): 
352         self.name=name
353         self.english_name=english_name
354
355
356 SHAPE_SPHERE=0
357 SHAPE_BOX=1
358 SHAPE_CAPSULE=2
359
360 RIGIDBODY_KINEMATICS=0
361 RIGIDBODY_PHYSICS=1
362 RIGIDBODY_PHYSICS_WITH_BONE=2
363
364
365 class RigidBody(object):
366     __slots__=['name', 
367             'bone_index', 
368             'collision_group', 
369             'no_collision_group', 
370             'shape_type',
371             'shape_size',
372             'shape_position', 
373             'shape_rotation', 
374             'mass',
375             'linear_damping', 
376             'angular_damping', 
377             'restitution', 
378             'friction', 
379             'mode'
380             ]
381     def __init__(self, name,
382             bone_index, 
383             collision_group, 
384             no_collision_group, 
385             mass,
386             linear_damping, 
387             angular_damping, 
388             restitution, 
389             friction, 
390             mode,
391             shape_type=0,
392             shape_size=common.Vector3(),
393             shape_position=common.Vector3(), 
394             shape_rotation=common.Vector3() 
395             ):
396         self.name=name
397         self.bone_index=bone_index
398         self.collision_group=collision_group 
399         self.no_collision_group=no_collision_group 
400         self.shape_type=shape_type
401         self.shape_size=shape_size
402         self.shape_position=shape_position
403         self.shape_rotation=shape_rotation
404         self.mass=mass
405         self.linear_damping=linear_damping
406         self.angular_damping=angular_damping
407         self.restitution=restitution
408         self.friction=friction
409         self.mode=mode
410
411     def __eq__(self, rhs):
412         return (
413                 self.name==rhs.name
414                 and self.bone_index==rhs.bone_index
415                 and self.collision_group==rhs.collision_group
416                 and self.no_collision_group==rhs.no_collision_group
417                 and self.shape_type==rhs.shape_type
418                 and self.shape_size==rhs.shape_size
419                 and self.shape_position==rhs.shape_position
420                 and self.shape_rotation==rhs.shape_rotation
421                 and self.mass==rhs.mass
422                 and self.linear_damping==rhs.linear_damping
423                 and self.angular_damping==rhs.angular_damping
424                 and self.restitution==rhs.restitution
425                 and self.friction==rhs.friction
426                 and self.mode==rhs.mode
427                 )
428
429
430 class Joint(object):
431     __slots__=[ 'name', 'rigidbody_index_a', 'rigidbody_index_b', 
432             'position', 'rotation',
433             'translation_limit_max', 'translation_limit_min',
434             'rotation_limit_max', 'rotation_limit_min',
435             'spring_constant_translation', 'spring_constant_rotation',
436             ]
437     def __init__(self, name,
438             rigidbody_index_a, rigidbody_index_b,
439             position, rotation,
440             translation_limit_max, translation_limit_min,
441             rotation_limit_max, rotation_limit_min,
442             spring_constant_translation, spring_constant_rotation
443             ):
444         self.name=name
445         self.rigidbody_index_a=rigidbody_index_a
446         self.rigidbody_index_b=rigidbody_index_b
447         self.position=position
448         self.rotation=rotation
449         self.translation_limit_max=translation_limit_max
450         self.translation_limit_min=translation_limit_min
451         self.rotation_limit_max=rotation_limit_max
452         self.rotation_limit_min=rotation_limit_min
453         self.spring_constant_translation=spring_constant_translation
454         self.spring_constant_rotation=spring_constant_rotation
455
456     def __eq__(self, rhs):
457         return (
458                 self.name==rhs.name
459                 and self.rigidbody_index_a==rhs.rigidbody_index_a
460                 and self.rigidbody_index_b==rhs.rigidbody_index_b
461                 and self.position==rhs.position
462                 and self.rotation==rhs.rotation
463                 and self.translation_limit_max==rhs.translation_limit_max
464                 and self.translation_limit_min==rhs.translation_limit_min
465                 and self.rotation_limit_max==rhs.rotation_limit_max
466                 and self.rotation_limit_min==rhs.rotation_limit_min
467                 and self.spring_constant_translation==rhs.spring_constant_translation
468                 and self.spring_constant_rotation==rhs.spring_constant_rotation
469                 )
470
471
472 class Model(object):
473     """pmd loader class.
474
475     Attributes:
476         io: internal use.
477         end: internal use.
478         pos: internal user.
479
480         version: pmd version number
481         _name: internal
482     """
483     __slots__=[
484             'version', 'name', 'comment',
485             'english_name', 'english_comment',
486             'vertices', 'indices', 'materials', 'bones', 
487             'ik_list', 'morphs',
488             'morph_indices', 'bone_group_list', 'bone_display_list',
489             'toon_textures',
490             'rigidbodies', 'joints',
491
492             'no_parent_bones',
493             ]
494     def __init__(self, version):
495         self.version=version
496         self.name=b''
497         self.comment=b''
498         self.english_name=b''
499         self.english_comment=b''
500         self.vertices=[]
501         self.indices=[]
502         self.materials=[]
503         self.bones=[]
504         self.ik_list=[]
505         self.morphs=[]
506         self.morph_indices=[]
507         self.bone_group_list=[]
508         self.bone_display_list=[]
509         # extend
510         self.toon_textures=[b'']*10
511         self.rigidbodies=[]
512         self.joints=[]
513         # innner use
514         self.no_parent_bones=[]
515
516     def each_vertex(self): return self.vertices
517     def getUV(self, i): return self.vertices[i].uv
518
519     def __str__(self):
520         return '<pmd-%g, "%s" vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
521             self.version, self.name, len(self.vertices), len(self.indices),
522             len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
523
524     def __eq__(self, rhs):
525         return (
526                 self.name==rhs.name
527                 and self.comment==rhs.comment
528                 and self.english_name==rhs.english_name
529                 and self.english_comment==rhs.english_comment
530                 and self.vertices==rhs.vertices
531                 and self.indices==rhs.indices
532                 and self.materials==rhs.materials
533                 and self.bones==rhs.bones
534                 and self.ik_list==rhs.ik_list
535                 and self.morphs==rhs.morphs
536                 and self.morph_indices==rhs.morph_indices
537                 and self.bone_group_list==rhs.bone_group_list
538                 and self.bone_display_list==rhs.bone_display_list
539                 and self.toon_textures==rhs.toon_textures
540                 and self.rigidbodies==rhs.rigidbodies
541                 and self.joints==rhs.joints
542                 )
543
544