4 http://yumin3123.at.webry.info/200810/article_4.html
5 http://atupdate.web.fc2.com/vmd_format.htm
9 class ShapeData(object):
11 morphing animation data.
13 __slots__=['name', 'frame', 'ratio']
14 def __init__(self, name):
19 def __cmp__(self, other):
20 return cmp(self.frame, other.frame)
22 class MotionData(object):
26 __slots__=['name', 'frame', 'pos', 'q', 'complement']
27 def __init__(self, name):
33 def __cmp__(self, other):
34 return cmp(self.frame, other.frame)
37 return '<MotionData "%s" %d %s%s>' % (self.name, self.frame, self.pos, self.q)
39 class VMDLoader(object):
40 __slots__=['io', 'end', 'signature',
41 'model_name', 'last_frame',
42 'motions', 'shapes', 'cameras', 'lights',
53 return '<VMDLoader model: "%s", motion: %d, shape: %d, camera: %d, light: %d>' % (
54 self.model_name, len(self.motions), len(self.shapes),
55 len(self.cameras), len(self.lights))
57 def load(self, path, io, end):
62 self.signature=truncate_zero(self.io.read(30))
63 version=self.validate_signature(self.signature)
65 print("invalid signature", self.signature)
69 if not self.load_verstion_1():
72 if not self.load_verstion_2():
75 raise Exception("unknown version")
81 if not m.name in self.motions:
82 self.motions[m.name]=[]
83 self.motions[m.name].append(m)
84 for name in self.motions.keys():
85 self.motions[name].sort()
90 if not s.name in self.shapes:
91 self.shapes[s.name]=[]
92 self.shapes[s.name].append(s)
93 for name in self.shapes.keys():
94 self.shapes[name].sort()
98 def getMotionCount(self):
100 for v in self.motions.values():
104 def getShapeCount(self):
106 for v in self.shapes.values():
110 def load_verstion_1(self):
112 self.model_name=truncate_zero(self.io.read(10))
113 if not self.loadMotion_1():
117 def loadMotion_1(self):
118 count=struct.unpack('H', self.io.read(2))[0]
120 for i in xrange(0, count):
124 ############################################################
125 def load_verstion_2(self):
127 self.model_name=truncate_zero(self.io.read(20))
129 if not self.loadMotion():
131 if not self.loadShape():
133 if not self.loadCamera():
135 if not self.loadLight():
137 #assert(self.io.tell()==self.end)
138 #self.motions.sort(lambda l, r: l.name<r.name)
142 def validate_signature(self, signature):
143 if self.signature == "Vocaloid Motion Data 0002":
145 if self.signature == "Vocaloid Motion Data file":
150 def loadMotion(self):
151 count=struct.unpack('I', self.io.read(4))[0]
152 for i in xrange(0, count):
157 count=struct.unpack('I', self.io.read(4))[0]
158 for i in xrange(0, count):
162 def loadCamera(self):
163 count=struct.unpack('I', self.io.read(4))[0]
164 for i in xrange(0, count):
171 count=struct.unpack('I', self.io.read(4))[0]
172 for i in xrange(0, count):
178 def loadFrameData(self):
182 data=MotionData(truncate_zero(self.io.read(15)))
183 (data.frame, data.pos.x, data.pos.y, data.pos.z,
184 data.q.x, data.q.y, data.q.z, data.q.w) = struct.unpack(
185 'I7f', self.io.read(32))
187 data.complement=''.join(
188 ['%x' % x for x in struct.unpack('64B', self.io.read(64))])
189 self.motions.append(data)
190 if data.frame>self.last_frame:
191 self.last_frame=data.frame
193 def loadShapeData(self):
197 data=ShapeData(truncate_zero(self.io.read(15)))
198 (data.frame, data.ratio)=struct.unpack('If', self.io.read(8))
199 self.shapes.append(data)
200 if data.frame>self.last_frame:
201 self.last_frame=data.frame
204 ############################################################
205 def create_csv_line(m):
206 # quaternion -> euler angle
207 (roll, pitch, yaw)=m.q.getRollPitchYaw()
208 return '%s,%d,%g,%g,%g,%g,%g,%g,0x%s\n' % (
209 m.name, m.frame, m.pos.x, m.pos.y, m.pos.z,
210 to_degree(pitch), to_degree(yaw), to_degree(roll), m.complement
213 def write_csv(l, path):
214 sys.setdefaultencoding('cp932')
216 csv.write('%s,0\n' % l.signature)
217 csv.write('%s\n' % l.model_name)
219 csv.write('%d\n' % len(l.motions))
221 csv.write(create_csv_line(m))
223 csv.write('%d\n' % len(l.shapes))
225 csv.write('%s,%d,%f\n' % ( s.name, s.frame, s.ratio))
227 csv.write('%d\n' % len(l.cameras))
228 for camera in l.cameras:
231 csv.write('%d\n' % len(l.lights))
232 for light in l.lights: