1 ###############################################################################
3 ###############################################################################
4 class ShapeData(object):
5 __slots__=['name', 'frame', 'ratio']
6 def __init__(self, name):
11 def __cmp__(self, other):
12 return cmp(self.frame, other.frame)
14 class MotionData(object):
15 __slots__=['name', 'frame', 'pos', 'q', 'complement']
16 def __init__(self, name):
22 def __cmp__(self, other):
23 return cmp(self.frame, other.frame)
26 return '<MotionData "%s" %d %s%s>' % (self.name, self.frame, self.pos, self.q)
28 class VMDLoader(object):
29 __slots__=['io', 'end', 'signature',
30 'model_name', 'last_frame',
31 'motions', 'shapes', 'cameras', 'lights',
42 return '<VMDLoader model: "%s", motion: %d, shape: %d, camera: %d, light: %d>' % (
43 self.model_name, len(self.motions), len(self.shapes),
44 len(self.cameras), len(self.lights))
46 def load(self, path, io, end):
51 self.signature=truncate_zero(self.io.read(30))
52 version=self.validate_signature(self.signature)
54 print("invalid signature", self.signature)
58 if not self.load_verstion_1():
61 if not self.load_verstion_2():
64 raise Exception("unknown version")
70 if not m.name in self.motions:
71 self.motions[m.name]=[]
72 self.motions[m.name].append(m)
73 for name in self.motions.keys():
74 self.motions[name].sort()
79 if not s.name in self.shapes:
80 self.shapes[s.name]=[]
81 self.shapes[s.name].append(s)
82 for name in self.shapes.keys():
83 self.shapes[name].sort()
87 def getMotionCount(self):
89 for v in self.motions.values():
93 def getShapeCount(self):
95 for v in self.shapes.values():
99 def load_verstion_1(self):
101 self.model_name=truncate_zero(self.io.read(10))
102 if not self.loadMotion_1():
106 def loadMotion_1(self):
107 count=struct.unpack('H', self.io.read(2))[0]
109 for i in xrange(0, count):
113 ############################################################
114 def load_verstion_2(self):
116 self.model_name=truncate_zero(self.io.read(20))
118 if not self.loadMotion():
120 if not self.loadShape():
122 if not self.loadCamera():
124 if not self.loadLight():
126 #assert(self.io.tell()==self.end)
127 #self.motions.sort(lambda l, r: l.name<r.name)
131 def validate_signature(self, signature):
132 if self.signature == "Vocaloid Motion Data 0002":
134 if self.signature == "Vocaloid Motion Data file":
139 def loadMotion(self):
140 count=struct.unpack('I', self.io.read(4))[0]
141 for i in xrange(0, count):
146 count=struct.unpack('I', self.io.read(4))[0]
147 for i in xrange(0, count):
151 def loadCamera(self):
152 count=struct.unpack('I', self.io.read(4))[0]
153 for i in xrange(0, count):
160 count=struct.unpack('I', self.io.read(4))[0]
161 for i in xrange(0, count):
167 def loadFrameData(self):
171 data=MotionData(truncate_zero(self.io.read(15)))
172 (data.frame, data.pos.x, data.pos.y, data.pos.z,
173 data.q.x, data.q.y, data.q.z, data.q.w) = struct.unpack(
174 'I7f', self.io.read(32))
176 data.complement=''.join(
177 ['%x' % x for x in struct.unpack('64B', self.io.read(64))])
178 self.motions.append(data)
179 if data.frame>self.last_frame:
180 self.last_frame=data.frame
182 def loadShapeData(self):
186 data=ShapeData(truncate_zero(self.io.read(15)))
187 (data.frame, data.ratio)=struct.unpack('If', self.io.read(8))
188 self.shapes.append(data)
189 if data.frame>self.last_frame:
190 self.last_frame=data.frame
193 ############################################################
194 def create_csv_line(m):
195 # quaternion -> euler angle
196 (roll, pitch, yaw)=m.q.getRollPitchYaw()
197 return '%s,%d,%g,%g,%g,%g,%g,%g,0x%s\n' % (
198 m.name, m.frame, m.pos.x, m.pos.y, m.pos.z,
199 to_degree(pitch), to_degree(yaw), to_degree(roll), m.complement
202 def write_csv(l, path):
203 sys.setdefaultencoding('cp932')
205 csv.write('%s,0\n' % l.signature)
206 csv.write('%s\n' % l.model_name)
208 csv.write('%d\n' % len(l.motions))
210 csv.write(create_csv_line(m))
212 csv.write('%d\n' % len(l.shapes))
214 csv.write('%s,%d,%f\n' % ( s.name, s.frame, s.ratio))
216 csv.write('%d\n' % len(l.cameras))
217 for camera in l.cameras:
220 csv.write('%d\n' % len(l.lights))
221 for light in l.lights: