OSDN Git Service

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