OSDN Git Service

implement rigidbody and constraint. fix for test
[meshio/pymeshio.git] / blender25-meshio / pymeshio / mmd.py
1 #!/usr/bin/python
2 # coding: utf-8
3 """
4 20091202: VPD読み込みを追加
5 20100318: PMD書き込みを追加
6 20100731: meshioと互換になるように改造
7
8 VMDの読み込み
9 http://yumin3123.at.webry.info/200810/article_4.html
10 http://atupdate.web.fc2.com/vmd_format.htm
11
12 PMDの読み込み
13 http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
14
15 VPDの読み込み
16
17 ToDo:
18     rigdid bodies
19     constraints
20 """
21 import sys
22 import codecs
23 import os.path
24 import struct
25 import math
26 import re
27 #import numpy
28 from decimal import *
29
30 ENCODING='cp932'
31
32 if sys.version_info[0]>=3:
33     xrange=range
34
35 ###############################################################################
36 # utility
37 ###############################################################################
38 def truncate_zero(src):
39     """
40     0x00以降を捨てる
41     """
42     pos = src.find(b"\x00")
43     assert(type(src)==bytes)
44     if pos >= 0:
45         return src[:pos]
46     else:
47         return src
48
49 def radian_to_degree(x):
50     return x/math.pi * 180.0
51
52
53 ###############################################################################
54 # geometry
55 ###############################################################################
56 class Vector2(object):
57     __slots__=['x', 'y']
58     def __init__(self, x=0, y=0):
59         self.x=x
60         self.y=y
61
62     def __str__(self):
63         return "<%f %f>" % (self.x, self.y)
64
65     def __getitem__(self, key):
66         if key==0:
67             return self.x
68         elif key==1:
69             return self.y
70         else:
71             assert(False)
72
73     def to_tuple(self):
74         return (self.x, self.y)
75
76
77 class Vector3(object):
78     __slots__=['x', 'y', 'z']
79     def __init__(self, x=0, y=0, z=0):
80         self.x=x
81         self.y=y
82         self.z=z
83
84     def __str__(self):
85         return "<%f %f %f>" % (self.x, self.y, self.z)
86
87     def __getitem__(self, key):
88         if key==0:
89             return self.x
90         elif key==1:
91             return self.y
92         elif key==2:
93             return self.z
94         else:
95             assert(False)
96
97     def to_tuple(self):
98         return (self.x, self.y, self.z)
99
100
101 class Quaternion(object):
102     __slots__=['x', 'y', 'z', 'w']
103     def __init__(self, x=0, y=0, z=0, w=1):
104         self.x=x
105         self.y=y
106         self.z=z
107         self.w=w
108
109     def __str__(self):
110         return "<%f %f %f %f>" % (self.x, self.y, self.z, self.w)
111
112     def __mul__(self, rhs):
113         u=numpy.array([self.x, self.y, self.z], 'f')
114         v=numpy.array([rhs.x, rhs.y, rhs.z], 'f')
115         xyz=self.w*v+rhs.w*u+numpy.cross(u, v)
116         q=Quaternion(xyz[0], xyz[1], xyz[2], self.w*rhs.w-numpy.dot(u, v))
117         return q
118
119     def dot(self, rhs):
120         return self.x*rhs.x+self.y*rhs.y+self.z*rhs.z+self.w*rhs.w
121
122     def getMatrix(self):
123         sqX=self.x*self.x
124         sqY=self.y*self.y
125         sqZ=self.z*self.z
126         xy=self.x*self.y
127         xz=self.x*self.z
128         yz=self.y*self.z
129         wx=self.w*self.x
130         wy=self.w*self.y
131         wz=self.w*self.z
132         return numpy.array([
133                 # 1
134                 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
135                 # 2
136                 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
137                 # 3
138                 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
139                 # 4
140                 [0, 0, 0, 1]],
141                 'f')
142
143     def getRHMatrix(self):
144         x=-self.x
145         y=-self.y
146         z=self.z
147         w=self.w
148         sqX=x*x
149         sqY=y*y
150         sqZ=z*z
151         xy=x*y
152         xz=x*z
153         yz=y*z
154         wx=w*x
155         wy=w*y
156         wz=w*z
157         return numpy.array([
158                 # 1
159                 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
160                 # 2
161                 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
162                 # 3
163                 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
164                 # 4
165                 [0, 0, 0, 1]],
166                 'f')
167
168     def getRollPitchYaw(self):
169         m=self.getMatrix()
170
171         roll = math.atan2(m[0, 1], m[1, 1])
172         pitch = math.asin(-m[2, 1])
173         yaw = math.atan2(m[2, 0], m[2, 2])
174
175         if math.fabs(math.cos(pitch)) < 1.0e-6:
176             roll += m[0, 1] > math.pi if 0.0 else -math.pi
177             yaw += m[2, 0] > math.pi if 0.0 else -math.pi
178
179         return roll, pitch, yaw
180
181     def getSqNorm(self):
182         return self.x*self.x+self.y*self.y+self.z*self.z+self.w*self.w
183
184     def getNormalized(self):
185         f=1.0/self.getSqNorm()
186         q=Quaternion(self.x*f, self.y*f, self.z*f, self.w*f)
187         return q
188
189     def getRightHanded(self):
190         "swap y and z axis"
191         return Quaternion(-self.x, -self.z, -self.y, self.w)
192
193     @staticmethod
194     def createFromAxisAngle(axis, rad):
195         q=Quaternion()
196         half_rad=rad/2.0
197         c=math.cos(half_rad)
198         s=math.sin(half_rad)
199         return Quaternion(axis[0]*s, axis[1]*s, axis[2]*s, c)
200
201
202 class RGBA(object):
203     __slots__=['r', 'g', 'b', 'a']
204     def __init__(self, r=0, g=0, b=0, a=1):
205         self.r=r
206         self.g=g
207         self.b=b
208         self.a=a
209
210     def __getitem__(self, key):
211         if key==0:
212             return self.r
213         elif key==1:
214             return self.g
215         elif key==2:
216             return self.b
217         elif key==3:
218             return self.a
219         else:
220             assert(False)
221
222
223
224
225 ###############################################################################
226 # interface
227 ###############################################################################
228 def load_pmd(path):
229     size=os.path.getsize(path)
230     f=open(path, "rb")
231     l=PMDLoader()
232     if l.load(path, f, size):
233         return l
234
235 def load_vmd(path):
236     size=os.path.getsize(path)
237     f=open(path, "rb")
238     l=VMDLoader()
239     if l.load(path, f, size):
240         return l
241
242 def load_vpd(path):
243     f=open(path, 'rb')
244     if not f:
245         return;
246     size=os.path.getsize(path)
247     l=VPDLoader()
248     if l.load(path, f, size):
249         return l
250
251
252 ###############################################################################
253 # debug
254 ###############################################################################
255 def debug_pmd(path):
256     l=load_pmd(path)
257     if not l:
258         print("fail to load")
259         sys.exit()
260
261     print(unicode(l).encode(ENCODING))
262     print(l.comment.encode(ENCODING))
263     print("<ボーン>".decode('utf-8').encode(ENCODING))
264     for bone in l.no_parent_bones:
265         print(bone.name.encode(ENCODING))
266         bone.display()
267     #for bone in l.bones:
268     #    uni="%s:%s" % (bone.english_name, bone.name)
269     #    print uni.encode(ENCODING)
270     #for skin in l.morph_list:
271     #    uni="%s:%s" % (skin.english_name, skin.name)
272     #    print uni.encode(ENCODING)
273     #for i, v in enumerate(l.vertices):
274     #    print i, v
275     #for i, f in enumerate(l.indices):
276     #    print i, f
277     for m in l.materials:
278         print(m)
279
280 def debug_pmd_write(path, out):
281     l=load_pmd(path)
282     if not l:
283         print("fail to load")
284         sys.exit()
285
286     if not l.write(out):
287         print("fail to write")
288         sys.exit()
289
290 def debug_vmd(path):
291     l=load_vmd(path)
292     if not l:
293         print("fail to load")
294         sys.exit()
295     print(unicode(l).encode(ENCODING))
296
297     #for m in l.motions[u'センター']:
298     #    print m.frame, m.pos
299     for n, m in l.shapes.items():
300         print(unicode(n).encode(ENCODING), getEnglishSkinName(n))
301
302 def debug_vpd(path):
303     l=load_vpd(path)
304     if not l:
305         print("fail to load")
306         sys.exit()
307     for bone in l.pose:
308         print(unicode(bone).encode(ENCODING))
309
310 if __name__=="__main__":
311     if len(sys.argv)<2:
312         print("usage: %s {pmd file}" % sys.argv[0])
313         print("usage: %s {vmd file}" % sys.argv[0])
314         print("usage: %s {vpd file}" % sys.argv[0])
315         print("usage: %s {pmd file} {export pmdfile}" % sys.argv[0])
316         sys.exit()
317
318     path=sys.argv[1]
319     if not os.path.exists(path):
320         print("no such file: %s" % path)
321
322     if path.lower().endswith('.pmd'):
323         if len(sys.argv)==2:
324             debug_pmd(path)
325         else:
326             debug_pmd_write(path, sys.argv[2])
327     elif path.lower().endswith('.vmd'):
328         debug_vmd(path)
329     elif path.lower().endswith('.vpd'):
330         debug_vpd(path)
331     else:
332         print("unknown file type: %s" % path)
333         sys.exit()
334