OSDN Git Service

fix refactoring
[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 import pymeshio.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=pymeshio.common.Vector3(0, 0, 0)
158         self.parent=None
159         self.ik_index=0xFFFF
160         self.pos=pymeshio.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(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='group'): self._name=name; self._english_name='center'
352
353
354 SHAPE_SPHERE=0
355 SHAPE_BOX=1
356 SHAPE_CAPSULE=2
357
358 RIGIDBODY_KINEMATICS=0
359 RIGIDBODY_PHYSICS=1
360 RIGIDBODY_PHYSICS_WITH_BONE=2
361
362
363 class RigidBody(object):
364     __slots__=['name', 
365             'bone_index', 
366             'collision_group', 
367             'no_collision_group', 
368             'shape_type',
369             'shape_size',
370             'shape_position', 
371             'shape_rotation', 
372             'mass',
373             'linear_damping', 
374             'angular_damping', 
375             'restitution', 
376             'friction', 
377             'mode'
378             ]
379     def __init__(self, name,
380             bone_index, 
381             collision_group, 
382             no_collision_group, 
383             shape_type,
384             shape_size,
385             shape_position, 
386             shape_rotation, 
387             mass,
388             linear_damping, 
389             angular_damping, 
390             restitution, 
391             friction, 
392             mode
393             ):
394         self.name=name
395         self.bone_index=bone_index
396         self.collision_group=collision_group 
397         self.no_collision_group=no_collision_group 
398         self.shape_type=shape_type
399         self.shape_size=shape_size
400         self.shape_position=shape_position
401         self.shape_rotation=shape_rotation
402         self.mass=mass
403         self.linear_damping=linear_damping
404         self.angular_damping=angular_damping
405         self.restitution=restitution
406         self.friction=friction
407         self.mode=mode
408
409     def __eq__(self, rhs):
410         return (
411                 self.name==rhs.name
412                 and self.bone_index==rhs.bone_index
413                 and self.collision_group==rhs.collision_group
414                 and self.no_collision_group==rhs.no_collision_group
415                 and self.shape_type==rhs.shape_type
416                 and self.shape_size==rhs.shape_size
417                 and self.shape_position==rhs.shape_position
418                 and self.shape_rotation==rhs.shape_rotation
419                 and self.mass==rhs.mass
420                 and self.linear_damping==rhs.linear_damping
421                 and self.angular_damping==rhs.angular_damping
422                 and self.restitution==rhs.restitution
423                 and self.friction==rhs.friction
424                 and self.mode==rhs.mode
425                 )
426
427
428 class Joint(object):
429     __slots__=[ 'name', 'rigidbody_index_a', 'rigidbody_index_b', 
430             'position', 'rotation',
431             'translation_limit_max', 'translation_limit_min',
432             'rotation_limit_max', 'rotation_limit_min',
433             'spring_constant_translation', 'spring_constant_rotation',
434             ]
435     def __init__(self, name,
436             rigidbody_index_a, rigidbody_index_b,
437             position, rotation,
438             translation_limit_max, translation_limit_min,
439             rotation_limit_max, rotation_limit_min,
440             spring_constant_translation, spring_constant_rotation
441             ):
442         self.name=name
443         self.rigidbody_index_a=rigidbody_index_a
444         self.rigidbody_index_b=rigidbody_index_b
445         self.position=position
446         self.rotation=rotation
447         self.translation_limit_max=translation_limit_max
448         self.translation_limit_min=translation_limit_min
449         self.rotation_limit_max=rotation_limit_max
450         self.rotation_limit_min=rotation_limit_min
451         self.spring_constant_translation=spring_constant_translation
452         self.spring_constant_rotation=spring_constant_rotation
453
454     def __eq__(self, rhs):
455         return (
456                 self.name==rhs.name
457                 and self.rigidbody_index_a==rhs.rigidbody_index_a
458                 and self.rigidbody_index_b==rhs.rigidbody_index_b
459                 and self.position==rhs.position
460                 and self.rotation==rhs.rotation
461                 and self.translation_limit_max==rhs.translation_limit_max
462                 and self.translation_limit_min==rhs.translation_limit_min
463                 and self.rotation_limit_max==rhs.rotation_limit_max
464                 and self.rotation_limit_min==rhs.rotation_limit_min
465                 and self.spring_constant_translation==rhs.spring_constant_translation
466                 and self.spring_constant_rotation==rhs.spring_constant_rotation
467                 )
468
469
470 class ToonTextures(object):
471     __slots__=['_toon_textures']
472     def __init__(self):
473         self._toon_textures=[]
474         for i in range(10):
475             self._toon_textures.append('toon%02d.bmp' % (i+1))
476
477     def __getitem__(self, key):
478         return from_str(self._toon_textures[key])
479
480     def __setitem__(self, key, value):
481         self._toon_textures[key]=to_str(value)
482
483     def __iter__(self):
484         for toon_texture in self._toon_textures:
485             yield from_str(toon_texture)
486
487
488 class Model(object):
489     """pmd loader class.
490
491     Attributes:
492         io: internal use.
493         end: internal use.
494         pos: internal user.
495
496         version: pmd version number
497         _name: internal
498     """
499     __slots__=[
500             'version', 'name', 'comment',
501             'english_name', 'english_comment',
502             'vertices', 'indices', 'materials', 'bones', 
503             'ik_list', 'morphs',
504             'morph_indices', 'bone_group_list', 'bone_display_list',
505             'bone_group_english_list',
506             'toon_textures',
507             'rigidbodies', 'joints',
508
509             'no_parent_bones',
510             ]
511     def __init__(self, version):
512         self.version=version
513         self.name=b''
514         self.comment=b''
515         self.english_name=b''
516         self.english_comment=b''
517         self.vertices=[]
518         self.indices=[]
519         self.materials=[]
520         self.bones=[]
521         self.ik_list=[]
522         self.morphs=[]
523         self.morph_indices=[]
524         self.bone_group_list=[]
525         self.bone_display_list=[]
526         # extend
527         self.bone_group_english_list=[]
528         self.toon_textures=ToonTextures()
529         self.rigidbodies=[]
530         self.joints=[]
531         # innner use
532         self.no_parent_bones=[]
533
534     def each_vertex(self): return self.vertices
535     def getUV(self, i): return self.vertices[i].uv
536
537     def __str__(self):
538         return '<pmd-%g, "%s" vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
539             self.version, self.name, len(self.vertices), len(self.indices),
540             len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
541
542     def __eq__(self, rhs):
543         return (
544                 self.name==rhs.name
545                 and self.comment==rhs.comment
546                 and self.english_name==rhs.english_name
547                 and self.english_comment==rhs.english_comment
548                 and self.vertices==rhs.vertices
549                 and self.indices==rhs.indices
550                 and self.materials==rhs.materials
551                 and self.bones==rhs.bones
552                 and self.ik_list==rhs.ik_list
553                 and self.morphs==rhs.morphs
554                 and self.morph_indices==rhs.morph_indices
555                 and self.bone_group_list==rhs.bone_group_list
556                 and self.bone_display_list==rhs.bone_display_list
557                 and self.bone_group_english_list==rhs.bone_group_english_list
558                 and self.toon_textures==rhs.toon_textures
559                 and self.rigidbodies==rhs.rigidbodies
560                 and self.joints==rhs.joints
561                 )
562
563