OSDN Git Service

implement rigidbody and constraint. fix for test
[meshio/pymeshio.git] / blender25-meshio / pymeshio / pmd.py
1 # coding: utf-8
2 import os
3 import struct
4 from mmd import *
5
6 ###############################################################################
7 # PMD
8 ###############################################################################
9 class Vertex(object):
10     __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
11     def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
12             bone0=0, bone1=0, weight0=0, edge_flag=0):
13         self.pos=Vector3(x, y, z)
14         self.normal=Vector3(nx, ny, nz)
15         self.uv=Vector2(u, v)
16         self.bone0=bone0
17         self.bone1=bone1
18         self.weight0=weight0
19         self.edge_flag=edge_flag
20
21     def __str__(self):
22         return "<%s %s %s, (%d, %d, %d)>" % (str(self.pos), str(self.normal), str(self.uv), self.bone0, self.bone1, self.weight0)
23
24     def __getitem__(self, key):
25         if key==0:
26             return self.pos.x
27         elif key==1:
28             return self.pos.y
29         elif key==2:
30             return self.pos.z
31         else:
32             assert(False)
33
34
35 class Material(object):
36     __slots__=[
37             'diffuse', 'shinness', 'specular',
38             'ambient', 'vertex_count', 'texture', 'toon_index', 'flag',
39             ]
40
41     def __init__(self, dr=0, dg=0, db=0, alpha=1, 
42             specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
43         self.diffuse=RGBA(dr, dg, db, alpha)
44         self.specular=RGBA(sr, sg, sb)
45         self.shinness=specular
46         self.ambient=RGBA(ar, ag, ab)
47         self.vertex_count=0
48         self.texture=''
49         self.toon_index=0
50         self.flag=0
51
52     def __str__(self):
53         return "<Material [%f, %f, %f, %f]>" % (
54                 self.diffuse[0], self.diffuse[1], 
55                 self.diffuse[2], self.diffuse[3],
56                 )
57
58     def getTexture(self): return self.texture.decode('cp932')
59     def setTexture(self, u): self.texture=u
60
61
62 # @return 各マテリアルについて、そのマテリアルが保持する面の回数だけ
63 # マテリアル自身を返す
64 def material_per_face(materials):
65     for m in materials:
66         for x in xrange(int(m.vertex_count/3)):
67             yield m
68
69
70 class Bone(object):
71     # kinds
72     ROTATE = 0
73     ROTATE_MOVE = 1
74     IK = 2
75     IK_ROTATE_INFL = 4
76     ROTATE_INFL = 5
77     IK_TARGET = 6
78     UNVISIBLE = 7
79     # since v4.0
80     ROLLING=8 # ?
81     TWEAK=9
82     __slots__=['name', 'index', 'type', 'parent', 'ik', 'pos',
83             'children', 'english_name', 'ik_index',
84             'parent_index', 'tail_index', 'tail',
85             ]
86     def __init__(self, name='bone', type=0):
87         self.name=name
88         self.index=0
89         self.type=type
90         self.parent_index=0xFFFF
91         self.tail_index=0
92         self.tail=Vector3(0, 0, 0)
93         self.parent=None
94         self.ik_index=0xFFFF
95         self.pos=Vector3(0, 0, 0)
96         self.children=[]
97         self.english_name=''
98
99     def getName(self): return self.name.decode('cp932')
100     def setName(self, u): self.name=u
101     def setEnglishName(self, u): self.english_name=u
102
103     def hasParent(self):
104         return self.parent_index!=0xFFFF
105
106     def hasChild(self):
107         return self.tail_index!=0
108
109     def display(self, indent=[]):
110         if len(indent)>0:
111             prefix=''
112             for i, is_end in enumerate(indent):
113                 if i==len(indent)-1:
114                     break
115                 else:
116                     prefix+='  ' if is_end else ' |'
117             uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
118             print(uni.encode(ENCODING))
119         else:
120             uni='%s(%s)' % (unicode(self), self.english_name)
121             print(uni.encode(ENCODING))
122
123         child_count=len(self.children)
124         for i in xrange(child_count):
125             child=self.children[i]
126             if i<child_count-1:
127                 child.display(indent+[False])
128             else:
129                 # last
130                 child.display(indent+[True])
131
132 # 0
133 class Bone_Rotate(Bone):
134     __slots__=[]
135     def __init__(self, name):
136         super(Bone_Rotate, self).__init__(name, 0)
137     def __str__(self):
138         return '<ROTATE %s>' % (self.name)
139 # 1
140 class Bone_RotateMove(Bone):
141     __slots__=[]
142     def __init__(self, name):
143         super(Bone_RotateMove, self).__init__(name, 1)
144     def __str__(self):
145         return '<ROTATE_MOVE %s>' % (self.name)
146 # 2
147 class Bone_IK(Bone):
148     __slots__=[]
149     def __init__(self, name):
150         super(Bone_IK, self).__init__(name, 2)
151     def __str__(self):
152         return '<IK %s>' % (self.name)
153 # 4
154 class Bone_IKRotateInfl(Bone):
155     __slots__=[]
156     def __init__(self, name):
157         super(Bone_IKRotateInfl, self).__init__(name, 4)
158     def __str__(self):
159         return '<IK_ROTATE_INFL %s>' % (self.name)
160 # 5
161 class Bone_RotateInfl(Bone):
162     __slots__=[]
163     def __init__(self, name):
164         super(Bone_RotateInfl, self).__init__(name, 5)
165     def __str__(self):
166         return '<ROTATE_INFL %s>' % (self.name)
167 # 6
168 class Bone_IKTarget(Bone):
169     __slots__=[]
170     def __init__(self, name):
171         super(Bone_IKTarget, self).__init__(name, 6)
172     def __str__(self):
173         return '<IK_TARGET %s>' % (self.name)
174 # 7
175 class Bone_Unvisible(Bone):
176     __slots__=[]
177     def __init__(self, name):
178         super(Bone_Unvisible, self).__init__(name, 7)
179     def __str__(self):
180         return '<UNVISIBLE %s>' % (self.name)
181 # 8
182 class Bone_Rolling(Bone):
183     __slots__=[]
184     def __init__(self, name):
185         super(Bone_Rolling, self).__init__(name, 8)
186     def __str__(self):
187         return '<ROLLING %s>' % (self.name)
188 # 9
189 class Bone_Tweak(Bone):
190     __slots__=[]
191     def __init__(self, name):
192         super(Bone_Tweak, self).__init__(name, 9)
193     def __str__(self):
194         return '<TWEAK %s>' % (self.name)
195
196
197 def createBone(name, type):
198     if type==0:
199         return Bone_Rotate(name)
200     elif type==1:
201         return Bone_RotateMove(name)
202     elif type==2:
203         return Bone_IK(name)
204     elif type==3:
205         raise Exception("no used bone type: 3(%s)" % name)
206     elif type==4:
207         return Bone_IKRotateInfl(name)
208     elif type==5:
209         return Bone_RotateInfl(name)
210     elif type==6:
211         return Bone_IKTarget(name)
212     elif type==7:
213         return Bone_Unvisible(name)
214     elif type==8:
215         return Bone_Rolling(name)
216     elif type==9:
217         return Bone_Tweak(name)
218     else:
219         raise Exception("unknown bone type: %d(%s)", type, name)
220
221
222 class IK(object):
223     __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
224     def __init__(self, index=0, target=0):
225         self.index=index
226         self.target=target
227         self.iterations=None
228         self.weight=None
229         self.children=[]
230
231     def __str__(self):
232         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))
233
234 class Skin(object):
235     __slots__=['name', 'type', 'indices', 'pos_list', 'english_name',
236             'vertex_count']
237     def __init__(self, name='skin'):
238         self.name=name
239         self.type=None
240         self.indices=[]
241         self.pos_list=[]
242         self.english_name=''
243         self.vertex_count=0
244
245     def getName(self): return self.name.decode('cp932')
246     def setName(self, u): self.name=u
247     def setEnglishName(self, u): self.english_name=u
248
249     def append(self, index, x, y, z):
250         self.indices.append(index)
251         self.pos_list.append(Vector3(x, y, z))
252
253     def __str__(self):
254         return '<Skin name: "%s", type: %d, vertex: %d>' % (
255             self.name, self.type, len(self.indices))
256
257
258 class ToonTexture(object):
259     __slots__=['name']
260     def __init__(self, name): self.name=name
261     def getName(self): return self.name.decode('cp932')
262     def setName(self, u): self.name=u
263
264
265 class BoneGroup(object):
266     __slots__=['name', 'english_name']
267     def __init__(self, name='group'): self.name=name; self.english_name='center'
268     def getName(self): return self.name.decode('cp932')
269     def setName(self, u): self.name=u
270     def getEnglishName(self): return self.english_name.decode('cp932')
271     def setEnglishName(self, u): self.english_name=u
272
273
274 class RigidBody(object):
275     __slots__=['name', 'boneIndex', 'group', 'target', 'shapeType',
276             'w', 'h', 'd', 'position', 'rotation', 'weight',
277             'linearDamping', 'angularDamping', 'restitution', 'friction', 'processType'
278             ]
279     def __init__(self, name):
280         self.name=name
281
282
283 class Constraint(object):
284     def __init__(self):
285         pass
286
287
288 class IO(object):
289     __slots__=['io', 'end', 'pos',
290             'version', 'name', 'comment',
291             'english_name', 'english_comment',
292             'vertices', 'indices', 'materials', 'bones', 
293             'ik_list', 'morph_list',
294             'face_list', 'bone_group_list', 'bone_display_list',
295             'toon_textures',
296             'no_parent_bones',
297             'rigidbodies', 'constraints',
298             ]
299     def __init__(self):
300         self.version=1.0
301         self.name=b"default"
302         self.comment=b"default"
303         self.english_name=b'default'
304         self.english_comment=b'default'
305         self.vertices=[]
306         self.indices=[]
307         self.materials=[]
308         self.bones=[]
309         self.ik_list=[]
310         self.morph_list=[]
311
312         self.face_list=[]
313         self.bone_group_list=[]
314         self.bone_display_list=[]
315
316         self.toon_textures=[
317                 ToonTexture(b'toon'), ToonTexture(b'toon'),
318                 ToonTexture(b'toon'), ToonTexture(b'toon'),
319                 ToonTexture(b'toon'), ToonTexture(b'toon'),
320                 ToonTexture(b'toon'), ToonTexture(b'toon'),
321                 ToonTexture(b'toon'), ToonTexture(b'toon'),
322                 ]
323
324         self.no_parent_bones=[]
325
326         self.rigidbodies=[]
327         self.constraints=[]
328
329     def getName(self): return self.name.decode('cp932')
330     def setName(self, u): self.name=u
331     def getComment(self): return self.comment.decode('cp932')
332     def setComment(self, u): self.comment=u
333     def getEnglishName(self): return self.english_name.decode('cp932')
334     def setEnglishName(self, u): self.english_name=u
335     def getEnglishComment(self): return self.english_comment.decode('cp932')
336     def setEnglishComment(self, u): self.english_comment=u
337
338     def getToonTexture(self, i): return self.toon_textures[i]
339     def each_vertex(self): return self.vertices
340     def getUV(self, i): return self.vertices[i].uv
341     def addVertex(self): 
342         v=Vertex()
343         self.vertices.append(v)
344         return v
345     def addMaterial(self):
346         m=Material()
347         self.materials.append(m)
348         return m
349     def addBone(self):
350         b=Bone()
351         self.bones.append(b)
352         return b
353     def addIK(self):
354         ik=IK()
355         self.ik_list.append(ik)
356         return ik
357     def addMorph(self):
358         s=Skin()
359         self.morph_list.append(s)
360         return s
361     def addBoneGroup(self):
362         g=BoneGroup()
363         self.bone_group_list.append(g)
364         return g
365     def addBoneDisplay(self, b, g):
366         self.bone_display_list.append((b, g))
367
368     def __str__(self):
369         return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
370             self.version, self.name, len(self.vertices), len(self.indices),
371             len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
372
373     def _check_position(self):
374         """
375         if self.pos:
376             print(self.pos, self.io.tell()-self.pos)
377         """
378         self.pos=self.io.tell()
379         pass
380
381     def read(self, path):
382         size=os.path.getsize(path)
383         f=open(path, "rb")
384         return self.load(path, f, size)
385
386     def load(self, path, io, end):
387         self.io=io
388         self.pos=self.io.tell()
389         self.end=end
390         self._check_position()
391
392         if not self._loadHeader():
393             return False
394         self._check_position()
395
396         if not self._loadVertex():
397             return False
398         self._check_position()
399
400         if not self._loadFace():
401             return False
402         self._check_position()
403
404         if not self._loadMaterial():
405             return False
406         self._check_position()
407
408         if not self._loadBone():
409             return False
410         self._check_position()
411
412         if not self._loadIK():
413             return False
414         self._check_position()
415
416         if not self._loadSkin():
417             return False
418         self._check_position()
419
420         if not self._loadSkinIndex():
421             return False
422         self._check_position()
423
424         if not self._loadBoneName():
425             return False
426         self._check_position()
427
428         if not self._loadBoneIndex():
429             return False
430         self._check_position()
431
432         if not self._loadExtend():
433             print('fail to loadExtend')
434             return False
435
436         # 終端
437         if self.io.tell()!=self.end:
438             print("can not reach eof.")
439             print("current: %d, end: %d, remain: %d" % (
440                     self.io.tell(), self.end, self.end-self.io.tell()))
441
442         # build bone tree
443         for i, child in enumerate(self.bones):
444             if child.parent_index==0xFFFF:
445                 # no parent
446                 self.no_parent_bones.append(child)
447                 child.parent=None
448             else:
449                 # has parent
450                 parent=self.bones[child.parent_index]
451                 child.parent=parent
452                 parent.children.append(child)
453             # 後位置
454             if child.hasChild():
455                 child.tail=self.bones[child.tail_index].pos
456
457         return True
458
459     def write(self, path):
460         io=open(path, 'wb')
461         if not io:
462             return False
463         # Header
464         io.write(b"Pmd")        
465         io.write(struct.pack("f", self.version))
466         io.write(struct.pack("20s", self.name))
467         io.write(struct.pack("256s", self.comment))
468
469         # Vertices
470         io.write(struct.pack("I", len(self.vertices)))
471         sVertex=struct.Struct("=8f2H2B") # 38byte
472         assert(sVertex.size==38)
473         for v in self.vertices:
474             data=sVertex.pack( 
475                 v.pos[0], v.pos[1], v.pos[2],
476                 v.normal[0], v.normal[1], v.normal[2],
477                 v.uv[0], v.uv[1],
478                 v.bone0, v.bone1, v.weight0, v.edge_flag)
479             io.write(data)
480
481         # Faces
482         io.write(struct.pack("I", len(self.indices)))
483         io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
484
485         # material
486         io.write(struct.pack("I", len(self.materials)))
487         sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
488         assert(sMaterial.size==70)
489         for m in self.materials:
490             io.write(sMaterial.pack(
491                 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
492                 m.shinness, 
493                 m.specular[0], m.specular[1], m.specular[2],
494                 m.ambient[0], m.ambient[1], m.ambient[2],
495                 m.toon_index, m.flag,
496                 m.vertex_count,
497                 m.texture
498                 ))
499
500         # bone
501         io.write(struct.pack("H", len(self.bones)))
502         sBone=struct.Struct("=20sHHBH3f")
503         assert(sBone.size==39)
504         for b in self.bones:
505             io.write(sBone.pack(
506                 b.name,
507                 b.parent_index, b.tail_index, b.type, b.ik_index,
508                 b.pos[0], b.pos[1], b.pos[2]))
509
510         # IK
511         io.write(struct.pack("H", len(self.ik_list)))
512         for ik in self.ik_list:
513             io.write(struct.pack("=2HBHf", 
514                 ik.index, ik.target, ik.length, ik.iterations, ik.weight
515                 ))
516             for c in ik.children:
517                 io.write(struct.pack("H", c))
518
519         # skin
520         io.write(struct.pack("H", len(self.morph_list)))
521         for s in self.morph_list:
522             io.write(struct.pack("20sIB", 
523                 s.name, len(s.indices), s.type))
524             for i, v in zip(s.indices, s.pos_list):
525                 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
526
527         # skin list
528         io.write(struct.pack("B", len(self.face_list)))
529         for i in self.face_list:
530             io.write(struct.pack("H", i))
531
532         # bone name
533         io.write(struct.pack("B", len(self.bone_group_list)))
534         for g in self.bone_group_list:
535             io.write(struct.pack("50s", g.name))
536
537         # bone list
538         io.write(struct.pack("I", len(self.bone_display_list)))
539         for l in self.bone_display_list:
540             io.write(struct.pack("=HB", *l))
541
542         # ToDo
543         # Extend Data
544
545         return True
546
547
548     def _loadExtend(self):
549         ############################################################
550         # extend1: english name
551         ############################################################
552         if self.io.tell()>=self.end:
553             return True
554         if struct.unpack("B", self.io.read(1))[0]==1:
555             if not self.loadEnglishName():
556                 return False
557         self._check_position()
558
559         ############################################################
560         # extend2: toon texture list
561         ############################################################
562         if self.io.tell()>=self.end:
563             return True
564         if not self.loadToonTexture():
565             return False
566         self._check_position()
567
568         ############################################################
569         # extend3: physics
570         ############################################################
571         if self.io.tell()>=self.end:
572             return True
573         if not self.loadPhysics():
574             return False
575         self._check_position()
576
577         return True
578
579     def _loadHeader(self):
580         signature=struct.unpack("3s", self.io.read(3))[0]
581         #print(signature)
582         if signature!=b"Pmd":
583             print("invalid signature", signature)
584             return False
585         self.version=struct.unpack("f", self.io.read(4))[0]
586         self.name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
587         self.comment = truncate_zero(
588                 struct.unpack("256s", self.io.read(256))[0])
589         return True
590
591     def _loadVertex(self):
592         count = struct.unpack("I", self.io.read(4))[0]
593         for i in xrange(count):
594             self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
595         return True
596
597     def _loadFace(self):
598         count = struct.unpack("I", self.io.read(4))[0]
599         for i in xrange(0, count, 3):
600             self.indices+=struct.unpack("HHH", self.io.read(6))
601         return True
602
603     def _loadMaterial(self):
604         count = struct.unpack("I", self.io.read(4))[0]
605         for i in xrange(count):
606             material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
607             material.toon_index=struct.unpack("B", self.io.read(1))[0]
608             material.flag=struct.unpack("B", self.io.read(1))[0]
609             material.vertex_count=struct.unpack("I", self.io.read(4))[0]
610             texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
611             # todo sphere map
612             #material.texture=texture.split('*')[0]
613             material.texture=texture
614             self.materials.append(material)
615         return True
616
617     def _loadBone(self):
618         size = struct.unpack("H", self.io.read(2))[0]
619         for i in xrange(size):
620             name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
621             parent_index, tail_index = struct.unpack("HH", self.io.read(4))
622             type = struct.unpack("B", self.io.read(1))[0]
623             bone=createBone(name, type)
624             bone.parent_index=parent_index
625             bone.tail_index=tail_index
626             bone.ik_index = struct.unpack("H", self.io.read(2))[0]
627             bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
628             bone.english_name="bone%03d" % len(self.bones)
629             self.bones.append(bone)
630         return True
631
632     def _loadIK(self):
633         size = struct.unpack("H", self.io.read(2))[0]
634         for i in xrange(size):
635             ik=IK(*struct.unpack("2H", self.io.read(4)))
636             ik.length = struct.unpack("B", self.io.read(1))[0]
637             ik.iterations = struct.unpack("H", self.io.read(2))[0]
638             ik.weight = struct.unpack("f", self.io.read(4))[0]
639             for j in xrange(ik.length):
640                 ik.children.append(struct.unpack("H", self.io.read(2))[0])
641             self.ik_list.append(ik)
642         return True
643
644     def _loadSkin(self):
645         size = struct.unpack("H", self.io.read(2))[0]
646         for i in xrange(size):
647             skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
648             skin_size = struct.unpack("I", self.io.read(4))[0]
649             skin.type = struct.unpack("B", self.io.read(1))[0]
650             for j in xrange(skin_size):
651                 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
652                 skin.pos_list.append(
653                         Vector3(*struct.unpack("3f", self.io.read(12))))
654             skin.english_name="skin%03d" % len(self.morph_list)
655             self.morph_list.append(skin)
656         return True
657
658     def _loadSkinIndex(self):
659         size = struct.unpack("B", self.io.read(1))[0]
660         for i in xrange(size):
661             self.face_list.append(struct.unpack("H", self.io.read(2))[0])
662         return True
663
664     def _loadBoneName(self):
665         size = struct.unpack("B", self.io.read(1))[0]
666         for i in xrange(size):
667             self.bone_group_list.append(BoneGroup(
668                 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
669         return True
670
671     def _loadBoneIndex(self):
672         size = struct.unpack("I", self.io.read(4))[0]
673         for i in xrange(size):
674             self.bone_display_list.append(struct.unpack("HB", self.io.read(3)))
675         return True
676
677     def loadToonTexture(self):
678         """
679         100bytex10
680         """
681         for i in xrange(10):
682             self.toon_textures.append(ToonTexture(
683                     truncate_zero(struct.unpack("100s", self.io.read(100))[0])))
684         return True
685
686     def loadEnglishName(self):
687         # english name
688         self.english_name=truncate_zero(
689                 struct.unpack("20s", self.io.read(20))[0])
690         self.english_comment=truncate_zero(
691                 struct.unpack("256s", self.io.read(256))[0])
692         # english bone list
693         for bone in self.bones:
694             english_name=truncate_zero(
695                     struct.unpack("20s", self.io.read(20))[0])
696             if english_name!=bone.name:
697                 bone.english_name=english_name
698         # english skin list
699         #for index in self.face_list:
700         for skin in self.morph_list:
701             if skin.name=='base':
702                 continue
703             english_name=truncate_zero(
704                     struct.unpack("20s", self.io.read(20))[0])
705             #skin=self.morph_list[index]
706             if english_name!=skin.name:
707                 skin.english_name=english_name
708         # english bone list
709         for i in xrange(0, len(self.bone_group_list)):
710             self.bone_group_list[i].english_name=truncate_zero(
711                     struct.unpack("50s", self.io.read(50))[0])
712         return True
713
714     def loadPhysics(self):
715         # 剛体リスト
716         count = struct.unpack("I", self.io.read(4))[0]
717         for i in xrange(count):
718             name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
719             rigidbody=RigidBody(name)
720             struct.unpack("63s", self.io.read(63))[0]
721             self.rigidbodies.append(rigidbody)
722
723         # ジョイントリスト
724         count = struct.unpack("I", self.io.read(4))[0]
725         for i in xrange(count):
726             struct.unpack("124s", self.io.read(124))[0]
727             constraint=Constraint()
728             self.constraints.append(Constraint)
729         return True
730