6 20100731: meshioと互換になるように改造
9 http://yumin3123.at.webry.info/200810/article_4.html
10 http://atupdate.web.fc2.com/vmd_format.htm
13 http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
32 if sys.version_info[0]>=3:
35 ###############################################################################
37 ###############################################################################
38 def truncate_zero(src):
42 pos = src.find(b"\x00")
43 assert(type(src)==bytes)
49 def radian_to_degree(x):
50 return x/math.pi * 180.0
53 ###############################################################################
55 ###############################################################################
56 class Vector2(object):
58 def __init__(self, x=0, y=0):
63 return "<%f %f>" % (self.x, self.y)
65 def __getitem__(self, key):
74 return (self.x, self.y)
77 class Vector3(object):
78 __slots__=['x', 'y', 'z']
79 def __init__(self, x=0, y=0, z=0):
85 return "<%f %f %f>" % (self.x, self.y, self.z)
87 def __getitem__(self, key):
98 return (self.x, self.y, self.z)
100 class Quaternion(object):
101 __slots__=['x', 'y', 'z', 'w']
102 def __init__(self, x=0, y=0, z=0, w=1):
109 return "<%f %f %f %f>" % (self.x, self.y, self.z, self.w)
111 def __mul__(self, rhs):
112 u=numpy.array([self.x, self.y, self.z], 'f')
113 v=numpy.array([rhs.x, rhs.y, rhs.z], 'f')
114 xyz=self.w*v+rhs.w*u+numpy.cross(u, v)
115 q=Quaternion(xyz[0], xyz[1], xyz[2], self.w*rhs.w-numpy.dot(u, v))
119 return self.x*rhs.x+self.y*rhs.y+self.z*rhs.z+self.w*rhs.w
133 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
135 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
137 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
142 def getRHMatrix(self):
158 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
160 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
162 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
167 def getRollPitchYaw(self):
170 roll = math.atan2(m[0, 1], m[1, 1])
171 pitch = math.asin(-m[2, 1])
172 yaw = math.atan2(m[2, 0], m[2, 2])
174 if math.fabs(math.cos(pitch)) < 1.0e-6:
175 roll += m[0, 1] > math.pi if 0.0 else -math.pi
176 yaw += m[2, 0] > math.pi if 0.0 else -math.pi
178 return roll, pitch, yaw
181 return self.x*self.x+self.y*self.y+self.z*self.z+self.w*self.w
183 def getNormalized(self):
184 f=1.0/self.getSqNorm()
185 q=Quaternion(self.x*f, self.y*f, self.z*f, self.w*f)
188 def getRightHanded(self):
190 return Quaternion(-self.x, -self.z, -self.y, self.w)
193 def createFromAxisAngle(axis, rad):
198 return Quaternion(axis[0]*s, axis[1]*s, axis[2]*s, c)
202 __slots__=['r', 'g', 'b', 'a']
203 def __init__(self, r=0, g=0, b=0, a=1):
209 def __getitem__(self, key):
222 ###############################################################################
224 ###############################################################################
225 class ShapeData(object):
226 __slots__=['name', 'frame', 'ratio']
227 def __init__(self, name):
232 def __cmp__(self, other):
233 return cmp(self.frame, other.frame)
235 class MotionData(object):
236 __slots__=['name', 'frame', 'pos', 'q', 'complement']
237 def __init__(self, name):
243 def __cmp__(self, other):
244 return cmp(self.frame, other.frame)
247 return '<MotionData "%s" %d %s%s>' % (self.name, self.frame, self.pos, self.q)
249 class VMDLoader(object):
250 __slots__=['io', 'end', 'signature',
251 'model_name', 'last_frame',
252 'motions', 'shapes', 'cameras', 'lights',
263 return '<VMDLoader model: "%s", motion: %d, shape: %d, camera: %d, light: %d>' % (
264 self.model_name, len(self.motions), len(self.shapes),
265 len(self.cameras), len(self.lights))
267 def load(self, path, io, end):
272 self.signature=truncate_zero(self.io.read(30))
273 version=self.validate_signature(self.signature)
275 print("invalid signature", self.signature)
279 if not self.load_verstion_1():
282 if not self.load_verstion_2():
285 raise Exception("unknown version")
291 if not m.name in self.motions:
292 self.motions[m.name]=[]
293 self.motions[m.name].append(m)
294 for name in self.motions.keys():
295 self.motions[name].sort()
300 if not s.name in self.shapes:
301 self.shapes[s.name]=[]
302 self.shapes[s.name].append(s)
303 for name in self.shapes.keys():
304 self.shapes[name].sort()
308 def getMotionCount(self):
310 for v in self.motions.values():
314 def getShapeCount(self):
316 for v in self.shapes.values():
320 def load_verstion_1(self):
322 self.model_name=truncate_zero(self.io.read(10))
323 if not self.loadMotion_1():
327 def loadMotion_1(self):
328 count=struct.unpack('H', self.io.read(2))[0]
330 for i in xrange(0, count):
334 ############################################################
335 def load_verstion_2(self):
337 self.model_name=truncate_zero(self.io.read(20))
339 if not self.loadMotion():
341 if not self.loadShape():
343 if not self.loadCamera():
345 if not self.loadLight():
347 #assert(self.io.tell()==self.end)
348 #self.motions.sort(lambda l, r: l.name<r.name)
352 def validate_signature(self, signature):
353 if self.signature == "Vocaloid Motion Data 0002":
355 if self.signature == "Vocaloid Motion Data file":
360 def loadMotion(self):
361 count=struct.unpack('I', self.io.read(4))[0]
362 for i in xrange(0, count):
367 count=struct.unpack('I', self.io.read(4))[0]
368 for i in xrange(0, count):
372 def loadCamera(self):
373 count=struct.unpack('I', self.io.read(4))[0]
374 for i in xrange(0, count):
381 count=struct.unpack('I', self.io.read(4))[0]
382 for i in xrange(0, count):
388 def loadFrameData(self):
392 data=MotionData(truncate_zero(self.io.read(15)))
393 (data.frame, data.pos.x, data.pos.y, data.pos.z,
394 data.q.x, data.q.y, data.q.z, data.q.w) = struct.unpack(
395 'I7f', self.io.read(32))
397 data.complement=''.join(
398 ['%x' % x for x in struct.unpack('64B', self.io.read(64))])
399 self.motions.append(data)
400 if data.frame>self.last_frame:
401 self.last_frame=data.frame
403 def loadShapeData(self):
407 data=ShapeData(truncate_zero(self.io.read(15)))
408 (data.frame, data.ratio)=struct.unpack('If', self.io.read(8))
409 self.shapes.append(data)
410 if data.frame>self.last_frame:
411 self.last_frame=data.frame
414 ############################################################
415 def create_csv_line(m):
416 # quaternion -> euler angle
417 (roll, pitch, yaw)=m.q.getRollPitchYaw()
418 return '%s,%d,%g,%g,%g,%g,%g,%g,0x%s\n' % (
419 m.name, m.frame, m.pos.x, m.pos.y, m.pos.z,
420 to_degree(pitch), to_degree(yaw), to_degree(roll), m.complement
423 def write_csv(l, path):
424 sys.setdefaultencoding('cp932')
426 csv.write('%s,0\n' % l.signature)
427 csv.write('%s\n' % l.model_name)
429 csv.write('%d\n' % len(l.motions))
431 csv.write(create_csv_line(m))
433 csv.write('%d\n' % len(l.shapes))
435 csv.write('%s,%d,%f\n' % ( s.name, s.frame, s.ratio))
437 csv.write('%d\n' % len(l.cameras))
438 for camera in l.cameras:
441 csv.write('%d\n' % len(l.lights))
442 for light in l.lights:
446 ###############################################################################
448 ###############################################################################
449 class Vertex(object):
450 __slots__=['pos', 'normal', 'uv', 'bone0', 'bone1', 'weight0', 'edge_flag']
451 def __init__(self, x=0, y=0, z=0, nx=0, ny=0, nz=0, u=0, v=0,
452 bone0=0, bone1=0, weight0=0, edge_flag=0):
453 self.pos=Vector3(x, y, z)
454 self.normal=Vector3(nx, ny, nz)
455 self.uv=Vector2(u, v)
459 self.edge_flag=edge_flag
462 return "<%s %s %s, (%d, %d, %d)>" % (str(self.pos), str(self.normal), str(self.uv), self.bone0, self.bone1, self.weight0)
464 def __getitem__(self, key):
474 class Material(object):
476 'diffuse', 'shinness', 'specular',
477 'ambient', 'vertex_count', 'texture', 'toon_index', 'flag',
480 def __init__(self, dr=0, dg=0, db=0, alpha=1,
481 specular=0, sr=0, sg=0, sb=0, ar=0, ag=0, ab=0):
482 self.diffuse=RGBA(dr, dg, db, alpha)
483 self.specular=RGBA(sr, sg, sb)
484 self.shinness=specular
485 self.ambient=RGBA(ar, ag, ab)
492 return "<Material [%f, %f, %f, %f]>" % (
493 self.diffuse[0], self.diffuse[1],
494 self.diffuse[2], self.diffuse[3],
497 def getTexture(self): return self.texture.decode('cp932')
498 def setTexture(self, u): self.texture=u
500 # @return 各マテリアルについて、そのマテリアルが保持する面の回数だけ
502 def material_per_face(materials):
504 for x in xrange(int(m.vertex_count/3)):
519 __slots__=['name', 'index', 'type', 'parent', 'ik', 'pos',
520 'children', 'english_name', 'ik_index',
521 'parent_index', 'tail_index', 'tail',
523 def __init__(self, name='bone', type=0):
527 self.parent_index=0xFFFF
529 self.tail=Vector3(0, 0, 0)
532 self.pos=Vector3(0, 0, 0)
536 def getName(self): return self.name.decode('cp932')
537 def setName(self, u): self.name=u
538 def setEnglishName(self, u): self.english_name=u
541 return self.parent_index!=0xFFFF
544 return self.tail_index!=0
546 def display(self, indent=[]):
549 for i, is_end in enumerate(indent):
553 prefix+=' ' if is_end else ' |'
554 uni='%s +%s(%s)' % (prefix, unicode(self), self.english_name)
555 print(uni.encode(ENCODING))
557 uni='%s(%s)' % (unicode(self), self.english_name)
558 print(uni.encode(ENCODING))
560 child_count=len(self.children)
561 for i in xrange(child_count):
562 child=self.children[i]
564 child.display(indent+[False])
567 child.display(indent+[True])
570 class Bone_Rotate(Bone):
572 def __init__(self, name):
573 super(Bone_Rotate, self).__init__(name, 0)
575 return '<ROTATE %s>' % (self.name)
577 class Bone_RotateMove(Bone):
579 def __init__(self, name):
580 super(Bone_RotateMove, self).__init__(name, 1)
582 return '<ROTATE_MOVE %s>' % (self.name)
586 def __init__(self, name):
587 super(Bone_IK, self).__init__(name, 2)
589 return '<IK %s>' % (self.name)
591 class Bone_IKRotateInfl(Bone):
593 def __init__(self, name):
594 super(Bone_IKRotateInfl, self).__init__(name, 4)
596 return '<IK_ROTATE_INFL %s>' % (self.name)
598 class Bone_RotateInfl(Bone):
600 def __init__(self, name):
601 super(Bone_RotateInfl, self).__init__(name, 5)
603 return '<ROTATE_INFL %s>' % (self.name)
605 class Bone_IKTarget(Bone):
607 def __init__(self, name):
608 super(Bone_IKTarget, self).__init__(name, 6)
610 return '<IK_TARGET %s>' % (self.name)
612 class Bone_Unvisible(Bone):
614 def __init__(self, name):
615 super(Bone_Unvisible, self).__init__(name, 7)
617 return '<UNVISIBLE %s>' % (self.name)
619 class Bone_Rolling(Bone):
621 def __init__(self, name):
622 super(Bone_Rolling, self).__init__(name, 8)
624 return '<ROLLING %s>' % (self.name)
626 class Bone_Tweak(Bone):
628 def __init__(self, name):
629 super(Bone_Tweak, self).__init__(name, 9)
631 return '<TWEAK %s>' % (self.name)
634 def createBone(name, type):
636 return Bone_Rotate(name)
638 return Bone_RotateMove(name)
642 raise Exception("no used bone type: 3(%s)" % name)
644 return Bone_IKRotateInfl(name)
646 return Bone_RotateInfl(name)
648 return Bone_IKTarget(name)
650 return Bone_Unvisible(name)
652 return Bone_Rolling(name)
654 return Bone_Tweak(name)
656 raise Exception("unknown bone type: %d(%s)", type, name)
660 __slots__=['index', 'target', 'iterations', 'weight', 'length', 'children']
661 def __init__(self, index=0, target=0):
669 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))
672 __slots__=['name', 'type', 'indices', 'pos_list', 'english_name',
674 def __init__(self, name='skin'):
682 def getName(self): return self.name.decode('cp932')
683 def setName(self, u): self.name=u
684 def setEnglishName(self, u): self.english_name=u
686 def append(self, index, x, y, z):
687 self.indices.append(index)
688 self.pos_list.append(Vector3(x, y, z))
691 return '<Skin name: "%s", type: %d, vertex: %d>' % (
692 self.name, self.type, len(self.indices))
694 class ToonTexture(object):
696 def __init__(self, name): self.name=name
697 def getName(self): return self.name.decode('cp932')
698 def setName(self, u): self.name=u
700 class BoneGroup(object):
701 __slots__=['name', 'english_name']
702 def __init__(self, name='group'): self.name=name; self.english_name='center'
703 def getName(self): return self.name.decode('cp932')
704 def setName(self, u): self.name=u
705 def getEnglishName(self): return self.english_name.decode('cp932')
706 def setEnglishName(self, u): self.english_name=u
708 class PMDLoader(object):
709 __slots__=['io', 'end', 'pos',
710 'version', 'model_name', 'comment',
711 'english_model_name', 'english_comment',
712 'vertices', 'indices', 'materials', 'bones',
713 'ik_list', 'morph_list',
714 'face_list', 'bone_group_list', 'bone_display_list',
717 'rigidbodies', 'constraints',
721 self.model_name=b"default"
722 self.comment=b"default"
723 self.english_model_name=b'default'
724 self.english_comment=b'default'
733 self.bone_group_list=[]
734 self.bone_display_list=[]
737 ToonTexture(b'toon'), ToonTexture(b'toon'),
738 ToonTexture(b'toon'), ToonTexture(b'toon'),
739 ToonTexture(b'toon'), ToonTexture(b'toon'),
740 ToonTexture(b'toon'), ToonTexture(b'toon'),
741 ToonTexture(b'toon'), ToonTexture(b'toon'),
744 self.no_parent_bones=[]
749 def getName(self): return self.model_name.decode('cp932')
750 def setName(self, u): self.model_name=u
751 def getComment(self): return self.comment.decode('cp932')
752 def setComment(self, u): self.comment=u
753 def getEnglishName(self): return self.english_model_name.decode('cp932')
754 def setEnglishName(self, u): self.english_model_name=u
755 def getEnglishComment(self): return self.english_comment.decode('cp932')
756 def setEnglishComment(self, u): self.english_comment=u
758 def getToonTexture(self, i): return self.toon_textures[i]
759 def each_vertex(self): return self.vertices
760 def getUV(self, i): return self.vertices[i].uv
763 self.vertices.append(v)
765 def addMaterial(self):
767 self.materials.append(m)
775 self.ik_list.append(ik)
779 self.morph_list.append(s)
781 def addBoneGroup(self):
783 self.bone_group_list.append(g)
785 def addBoneDisplay(self, b, g):
786 self.bone_display_list.append((b, g))
789 return '<PMDLoader version: %g, model: "%s", vertex: %d, face: %d, material: %d, bone: %d ik: %d, skin: %d>' % (
790 self.version, self.model_name, len(self.vertices), len(self.indices),
791 len(self.materials), len(self.bones), len(self.ik_list), len(self.morph_list))
793 def _check_position(self):
796 print(self.pos, self.io.tell()-self.pos)
798 self.pos=self.io.tell()
801 def read(self, path):
802 size=os.path.getsize(path)
804 return self.load(path, f, size)
806 def load(self, path, io, end):
808 self.pos=self.io.tell()
810 self._check_position()
812 if not self._loadHeader():
814 self._check_position()
816 if not self._loadVertex():
818 self._check_position()
820 if not self._loadFace():
822 self._check_position()
824 if not self._loadMaterial():
826 self._check_position()
828 if not self._loadBone():
830 self._check_position()
832 if not self._loadIK():
834 self._check_position()
836 if not self._loadSkin():
838 self._check_position()
840 if not self._loadSkinIndex():
842 self._check_position()
844 if not self._loadBoneName():
846 self._check_position()
848 if not self._loadBoneIndex():
850 self._check_position()
852 if not self._loadExtend():
853 print('fail to loadExtend')
857 if self.io.tell()!=self.end:
858 print("can not reach eof.")
859 print("current: %d, end: %d, remain: %d" % (
860 self.io.tell(), self.end, self.end-self.io.tell()))
863 for i, child in enumerate(self.bones):
864 if child.parent_index==0xFFFF:
866 self.no_parent_bones.append(child)
870 parent=self.bones[child.parent_index]
872 parent.children.append(child)
875 child.tail=self.bones[child.tail_index].pos
879 def write(self, path):
885 io.write(struct.pack("f", self.version))
886 io.write(struct.pack("20s", self.model_name))
887 io.write(struct.pack("256s", self.comment))
890 io.write(struct.pack("I", len(self.vertices)))
891 sVertex=struct.Struct("=8f2H2B") # 38byte
892 assert(sVertex.size==38)
893 for v in self.vertices:
895 v.pos[0], v.pos[1], v.pos[2],
896 v.normal[0], v.normal[1], v.normal[2],
898 v.bone0, v.bone1, v.weight0, v.edge_flag)
902 io.write(struct.pack("I", len(self.indices)))
903 io.write(struct.pack("=%dH" % len(self.indices), *self.indices))
906 io.write(struct.pack("I", len(self.materials)))
907 sMaterial=struct.Struct("=3fff3f3fBBI20s") # 70byte
908 assert(sMaterial.size==70)
909 for m in self.materials:
910 io.write(sMaterial.pack(
911 m.diffuse[0], m.diffuse[1], m.diffuse[2], m.diffuse[3],
913 m.specular[0], m.specular[1], m.specular[2],
914 m.ambient[0], m.ambient[1], m.ambient[2],
915 m.toon_index, m.flag,
921 io.write(struct.pack("H", len(self.bones)))
922 sBone=struct.Struct("=20sHHBH3f")
923 assert(sBone.size==39)
927 b.parent_index, b.tail_index, b.type, b.ik_index,
928 b.pos[0], b.pos[1], b.pos[2]))
931 io.write(struct.pack("H", len(self.ik_list)))
932 for ik in self.ik_list:
933 io.write(struct.pack("=2HBHf",
934 ik.index, ik.target, ik.length, ik.iterations, ik.weight
936 for c in ik.children:
937 io.write(struct.pack("H", c))
940 io.write(struct.pack("H", len(self.morph_list)))
941 for s in self.morph_list:
942 io.write(struct.pack("20sIB",
943 s.name, len(s.indices), s.type))
944 for i, v in zip(s.indices, s.pos_list):
945 io.write(struct.pack("I3f", i, v[0], v[1], v[2]))
948 io.write(struct.pack("B", len(self.face_list)))
949 for i in self.face_list:
950 io.write(struct.pack("H", i))
953 io.write(struct.pack("B", len(self.bone_group_list)))
954 for g in self.bone_group_list:
955 io.write(struct.pack("50s", g.name))
958 io.write(struct.pack("I", len(self.bone_display_list)))
959 for l in self.bone_display_list:
960 io.write(struct.pack("=HB", *l))
968 def _loadExtend(self):
969 ############################################################
970 # extend1: english name
971 ############################################################
972 if self.io.tell()>=self.end:
974 if struct.unpack("B", self.io.read(1))[0]==1:
975 if not self.loadEnglishName():
977 self._check_position()
979 ############################################################
980 # extend2: toon texture list
981 ############################################################
982 if self.io.tell()>=self.end:
984 if not self.loadToonTexture():
986 self._check_position()
988 ############################################################
990 ############################################################
991 if self.io.tell()>=self.end:
993 #if not self.loadPhysics():
995 self._check_position()
999 def _loadHeader(self):
1000 signature=struct.unpack("3s", self.io.read(3))[0]
1002 if signature!=b"Pmd":
1003 print("invalid signature", signature)
1005 self.version=struct.unpack("f", self.io.read(4))[0]
1006 self.model_name = truncate_zero(struct.unpack("20s", self.io.read(20))[0])
1007 self.comment = truncate_zero(
1008 struct.unpack("256s", self.io.read(256))[0])
1011 def _loadVertex(self):
1012 count = struct.unpack("I", self.io.read(4))[0]
1013 for i in xrange(count):
1014 self.vertices.append(Vertex(*struct.unpack("8f2H2B", self.io.read(38))))
1017 def _loadFace(self):
1018 count = struct.unpack("I", self.io.read(4))[0]
1019 for i in xrange(0, count, 3):
1020 self.indices+=struct.unpack("HHH", self.io.read(6))
1023 def _loadMaterial(self):
1024 count = struct.unpack("I", self.io.read(4))[0]
1025 for i in xrange(count):
1026 material=Material(*struct.unpack("4ff3f3f", self.io.read(44)))
1027 material.toon_index=struct.unpack("B", self.io.read(1))[0]
1028 material.flag=struct.unpack("B", self.io.read(1))[0]
1029 material.vertex_count=struct.unpack("I", self.io.read(4))[0]
1030 texture=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
1032 #material.texture=texture.split('*')[0]
1033 material.texture=texture
1034 self.materials.append(material)
1037 def _loadBone(self):
1038 size = struct.unpack("H", self.io.read(2))[0]
1039 for i in xrange(size):
1040 name=truncate_zero(struct.unpack("20s", self.io.read(20))[0])
1041 parent_index, tail_index = struct.unpack("HH", self.io.read(4))
1042 type = struct.unpack("B", self.io.read(1))[0]
1043 bone=createBone(name, type)
1044 bone.parent_index=parent_index
1045 bone.tail_index=tail_index
1046 bone.ik_index = struct.unpack("H", self.io.read(2))[0]
1047 bone.pos = Vector3(*struct.unpack("3f", self.io.read(12)))
1048 bone.english_name="bone%03d" % len(self.bones)
1049 self.bones.append(bone)
1053 size = struct.unpack("H", self.io.read(2))[0]
1054 for i in xrange(size):
1055 ik=IK(*struct.unpack("2H", self.io.read(4)))
1056 ik.length = struct.unpack("B", self.io.read(1))[0]
1057 ik.iterations = struct.unpack("H", self.io.read(2))[0]
1058 ik.weight = struct.unpack("f", self.io.read(4))[0]
1059 for j in xrange(ik.length):
1060 ik.children.append(struct.unpack("H", self.io.read(2))[0])
1061 self.ik_list.append(ik)
1064 def _loadSkin(self):
1065 size = struct.unpack("H", self.io.read(2))[0]
1066 for i in xrange(size):
1067 skin=Skin(truncate_zero(struct.unpack("20s", self.io.read(20))[0]))
1068 skin_size = struct.unpack("I", self.io.read(4))[0]
1069 skin.type = struct.unpack("B", self.io.read(1))[0]
1070 for j in xrange(skin_size):
1071 skin.indices.append(struct.unpack("I", self.io.read(4))[0])
1072 skin.pos_list.append(
1073 Vector3(*struct.unpack("3f", self.io.read(12))))
1074 skin.english_name="skin%03d" % len(self.morph_list)
1075 self.morph_list.append(skin)
1078 def _loadSkinIndex(self):
1079 size = struct.unpack("B", self.io.read(1))[0]
1080 for i in xrange(size):
1081 self.face_list.append(struct.unpack("H", self.io.read(2))[0])
1084 def _loadBoneName(self):
1085 size = struct.unpack("B", self.io.read(1))[0]
1086 for i in xrange(size):
1087 self.bone_group_list.append(BoneGroup(
1088 truncate_zero(struct.unpack("50s", self.io.read(50))[0])))
1091 def _loadBoneIndex(self):
1092 size = struct.unpack("I", self.io.read(4))[0]
1093 for i in xrange(size):
1094 self.bone_display_list.append(struct.unpack("HB", self.io.read(3)))
1097 def loadToonTexture(self):
1101 for i in xrange(10):
1102 self.toon_textures.append(ToonTexture(
1103 truncate_zero(struct.unpack("100s", self.io.read(100))[0])))
1106 def loadEnglishName(self):
1108 self.english_model_name=truncate_zero(
1109 struct.unpack("20s", self.io.read(20))[0])
1110 self.english_comment=truncate_zero(
1111 struct.unpack("256s", self.io.read(256))[0])
1113 for bone in self.bones:
1114 english_name=truncate_zero(
1115 struct.unpack("20s", self.io.read(20))[0])
1116 if english_name!=bone.name:
1117 bone.english_name=english_name
1119 #for index in self.face_list:
1120 for skin in self.morph_list:
1121 if skin.name=='base':
1123 english_name=truncate_zero(
1124 struct.unpack("20s", self.io.read(20))[0])
1125 #skin=self.morph_list[index]
1126 if english_name!=skin.name:
1127 skin.english_name=english_name
1129 for i in xrange(0, len(self.bone_group_list)):
1130 self.bone_group_list[i].english_name=truncate_zero(
1131 struct.unpack("50s", self.io.read(50))[0])
1134 def loadPhysics(self):
1136 count = struct.unpack("I", self.io.read(4))[0]
1137 for i in xrange(count):
1138 struct.unpack("83s", self.io.read(83))[0]
1140 count = struct.unpack("I", self.io.read(4))[0]
1141 for i in xrange(count):
1142 struct.unpack("124s", self.io.read(124))[0]
1146 ###############################################################################
1148 ###############################################################################
1149 class LineLoader(object):
1153 __slots__=['path', 'io', 'end']
1155 return "<%s current:%d, end:%d>" % (
1156 self.__class__, self.getPos(), self.getEnd())
1159 return self.io.tell()
1165 return (self.io.readline()).strip()
1168 return self.io.tell()>=self.end
1170 def load(self, path, io, end):
1174 return self.process()
1180 while not self.isEnd():
1185 class VPDLoader(LineLoader):
1188 super(VPDLoader, self).__init__()
1192 return "<VPD poses:%d>" % len(self.pose)
1195 if self.readline()!="Vocaloid Pose Data file":
1198 RE_OPEN=re.compile('^(\w+){(.*)')
1199 RE_OSM=re.compile('^\w+\.osm;')
1200 RE_COUNT=re.compile('^(\d+);')
1203 while not self.isEnd():
1204 line=self.readline()
1207 m=RE_OPEN.match(line)
1209 if not self.parseBone(m.group(2)):
1210 raise Exception("invalid bone")
1213 m=RE_OSM.match(line)
1217 m=RE_COUNT.match(line)
1219 bone_count=int(m.group(1))
1222 return len(self.pose)==bone_count
1224 def parseBone(self, name):
1225 bone=MotionData(name)
1226 self.pose.append(bone)
1227 bone.pos=Vector3(*[float(token) for token in self.readline().split(';')[0].split(',')])
1228 bone.q=Quaternion(*[float(token) for token in self.readline().split(';')[0].split(',')])
1229 return self.readline()=="}"
1232 ###############################################################################
1234 ###############################################################################
1236 size=os.path.getsize(path)
1239 if l.load(path, f, size):
1243 size=os.path.getsize(path)
1246 if l.load(path, f, size):
1253 size=os.path.getsize(path)
1255 if l.load(path, f, size):
1259 ###############################################################################
1261 ###############################################################################
1262 def debug_pmd(path):
1265 print("fail to load")
1268 print(unicode(l).encode(ENCODING))
1269 print(l.comment.encode(ENCODING))
1270 print("<ボーン>".decode('utf-8').encode(ENCODING))
1271 for bone in l.no_parent_bones:
1272 print(bone.name.encode(ENCODING))
1274 #for bone in l.bones:
1275 # uni="%s:%s" % (bone.english_name, bone.name)
1276 # print uni.encode(ENCODING)
1277 #for skin in l.morph_list:
1278 # uni="%s:%s" % (skin.english_name, skin.name)
1279 # print uni.encode(ENCODING)
1280 #for i, v in enumerate(l.vertices):
1282 #for i, f in enumerate(l.indices):
1284 for m in l.materials:
1287 def debug_pmd_write(path, out):
1290 print("fail to load")
1293 if not l.write(out):
1294 print("fail to write")
1297 def debug_vmd(path):
1300 print("fail to load")
1302 print(unicode(l).encode(ENCODING))
1304 #for m in l.motions[u'センター']:
1305 # print m.frame, m.pos
1306 for n, m in l.shapes.items():
1307 print(unicode(n).encode(ENCODING), getEnglishSkinName(n))
1309 def debug_vpd(path):
1312 print("fail to load")
1315 print(unicode(bone).encode(ENCODING))
1317 if __name__=="__main__":
1319 print("usage: %s {pmd file}" % sys.argv[0])
1320 print("usage: %s {vmd file}" % sys.argv[0])
1321 print("usage: %s {vpd file}" % sys.argv[0])
1322 print("usage: %s {pmd file} {export pmdfile}" % sys.argv[0])
1326 if not os.path.exists(path):
1327 print("no such file: %s" % path)
1329 if path.lower().endswith('.pmd'):
1330 if len(sys.argv)==2:
1333 debug_pmd_write(path, sys.argv[2])
1334 elif path.lower().endswith('.vmd'):
1336 elif path.lower().endswith('.vpd'):
1339 print("unknown file type: %s" % path)