OSDN Git Service

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