OSDN Git Service

5a1614ac3e32ea0e040ae96750dd121860c8179c
[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 class Quaternion(object):
101     __slots__=['x', 'y', 'z', 'w']
102     def __init__(self, x=0, y=0, z=0, w=1):
103         self.x=x
104         self.y=y
105         self.z=z
106         self.w=w
107
108     def __str__(self):
109         return "<%f %f %f %f>" % (self.x, self.y, self.z, self.w)
110
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))
116         return q
117
118     def dot(self, rhs):
119         return self.x*rhs.x+self.y*rhs.y+self.z*rhs.z+self.w*rhs.w
120
121     def getMatrix(self):
122         sqX=self.x*self.x
123         sqY=self.y*self.y
124         sqZ=self.z*self.z
125         xy=self.x*self.y
126         xz=self.x*self.z
127         yz=self.y*self.z
128         wx=self.w*self.x
129         wy=self.w*self.y
130         wz=self.w*self.z
131         return numpy.array([
132                 # 1
133                 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
134                 # 2
135                 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
136                 # 3
137                 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
138                 # 4
139                 [0, 0, 0, 1]],
140                 'f')
141
142     def getRHMatrix(self):
143         x=-self.x
144         y=-self.y
145         z=self.z
146         w=self.w
147         sqX=x*x
148         sqY=y*y
149         sqZ=z*z
150         xy=x*y
151         xz=x*z
152         yz=y*z
153         wx=w*x
154         wy=w*y
155         wz=w*z
156         return numpy.array([
157                 # 1
158                 [1-2*sqY-2*sqZ, 2*xy+2*wz, 2*xz-2*wy, 0],
159                 # 2
160                 [2*xy-2*wz, 1-2*sqX-2*sqZ, 2*yz+2*wx, 0],
161                 # 3
162                 [2*xz+2*wy, 2*yz-2*wx, 1-2*sqX-2*sqY, 0],
163                 # 4
164                 [0, 0, 0, 1]],
165                 'f')
166
167     def getRollPitchYaw(self):
168         m=self.getMatrix()
169
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])
173
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
177
178         return roll, pitch, yaw
179
180     def getSqNorm(self):
181         return self.x*self.x+self.y*self.y+self.z*self.z+self.w*self.w
182
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)
186         return q
187
188     def getRightHanded(self):
189         "swap y and z axis"
190         return Quaternion(-self.x, -self.z, -self.y, self.w)
191
192     @staticmethod
193     def createFromAxisAngle(axis, rad):
194         q=Quaternion()
195         half_rad=rad/2.0
196         c=math.cos(half_rad)
197         s=math.sin(half_rad)
198         return Quaternion(axis[0]*s, axis[1]*s, axis[2]*s, c)
199
200
201 class RGBA(object):
202     __slots__=['r', 'g', 'b', 'a']
203     def __init__(self, r=0, g=0, b=0, a=1):
204         self.r=r
205         self.g=g
206         self.b=b
207         self.a=a
208
209     def __getitem__(self, key):
210         if key==0:
211             return self.r
212         elif key==1:
213             return self.g
214         elif key==2:
215             return self.b
216         elif key==3:
217             return self.a
218         else:
219             assert(False)
220
221
222
223
224 ###############################################################################
225 # interface
226 ###############################################################################
227 def load_pmd(path):
228     size=os.path.getsize(path)
229     f=open(path, "rb")
230     l=PMDLoader()
231     if l.load(path, f, size):
232         return l
233
234 def load_vmd(path):
235     size=os.path.getsize(path)
236     f=open(path, "rb")
237     l=VMDLoader()
238     if l.load(path, f, size):
239         return l
240
241 def load_vpd(path):
242     f=open(path, 'rb')
243     if not f:
244         return;
245     size=os.path.getsize(path)
246     l=VPDLoader()
247     if l.load(path, f, size):
248         return l
249
250
251 ###############################################################################
252 # debug
253 ###############################################################################
254 def debug_pmd(path):
255     l=load_pmd(path)
256     if not l:
257         print("fail to load")
258         sys.exit()
259
260     print(unicode(l).encode(ENCODING))
261     print(l.comment.encode(ENCODING))
262     print("<ボーン>".decode('utf-8').encode(ENCODING))
263     for bone in l.no_parent_bones:
264         print(bone.name.encode(ENCODING))
265         bone.display()
266     #for bone in l.bones:
267     #    uni="%s:%s" % (bone.english_name, bone.name)
268     #    print uni.encode(ENCODING)
269     #for skin in l.morph_list:
270     #    uni="%s:%s" % (skin.english_name, skin.name)
271     #    print uni.encode(ENCODING)
272     #for i, v in enumerate(l.vertices):
273     #    print i, v
274     #for i, f in enumerate(l.indices):
275     #    print i, f
276     for m in l.materials:
277         print(m)
278
279 def debug_pmd_write(path, out):
280     l=load_pmd(path)
281     if not l:
282         print("fail to load")
283         sys.exit()
284
285     if not l.write(out):
286         print("fail to write")
287         sys.exit()
288
289 def debug_vmd(path):
290     l=load_vmd(path)
291     if not l:
292         print("fail to load")
293         sys.exit()
294     print(unicode(l).encode(ENCODING))
295
296     #for m in l.motions[u'センター']:
297     #    print m.frame, m.pos
298     for n, m in l.shapes.items():
299         print(unicode(n).encode(ENCODING), getEnglishSkinName(n))
300
301 def debug_vpd(path):
302     l=load_vpd(path)
303     if not l:
304         print("fail to load")
305         sys.exit()
306     for bone in l.pose:
307         print(unicode(bone).encode(ENCODING))
308
309 if __name__=="__main__":
310     if len(sys.argv)<2:
311         print("usage: %s {pmd file}" % sys.argv[0])
312         print("usage: %s {vmd file}" % sys.argv[0])
313         print("usage: %s {vpd file}" % sys.argv[0])
314         print("usage: %s {pmd file} {export pmdfile}" % sys.argv[0])
315         sys.exit()
316
317     path=sys.argv[1]
318     if not os.path.exists(path):
319         print("no such file: %s" % path)
320
321     if path.lower().endswith('.pmd'):
322         if len(sys.argv)==2:
323             debug_pmd(path)
324         else:
325             debug_pmd_write(path, sys.argv[2])
326     elif path.lower().endswith('.vmd'):
327         debug_vmd(path)
328     elif path.lower().endswith('.vpd'):
329         debug_vpd(path)
330     else:
331         print("unknown file type: %s" % path)
332         sys.exit()
333