Add simple NTO viewer
[dormin.git] / reeng / statanb.py
blob024aed35324f1303f8f149026e6478e7d8112d9c
1 #!/usr/bin/env python
3 maxd = [(-1e9, "none", -1, -1) for i in range (8)]
4 mind = [( 1e9, "none", -1, -1) for i in range (8)]
6 import sys, math, os
7 from struct import unpack
9 class Continue:
10 pass
12 def magn (F):
13 return math.sqrt (reduce (lambda a,b:b*b+a, F,0))
15 def bitstr (b, l):
16 # boy, am i proud for this...
17 return reduce(lambda s,v:"01"[v]+s,[(b>>i)&1 for i in range(l)],"")
19 def makelut (i):
20 bitindex = 32
21 lut = []
22 for j in range (4):
23 bitlen = [9,5][j == i]
24 bitindex -= bitlen
25 lut.append ((bitindex, bitlen))
26 return lut
28 bitlut = [makelut (i) for i in range (4)]
30 def kalms (val, len):
31 a = 0
32 if len == 9:
33 lut = [-256, +128, +64, +32, +16, +8, +4, +2, +1]
34 for i in range (len):
35 if val & (1 << i):
36 a += lut[8-i]
37 else:
38 lut = [-16, +8, +4, +2, +1]
39 for i in range (len):
40 if val & (1 << i):
41 a += lut[4-i]
43 return a
45 def notkalms (v, len):
46 return v
48 kalms=notkalms
50 def fkalms (v, len):
51 a = kalms (v, len)
52 x = (a + 256) / 512.0
53 y = math.acos (x) * 57.2957795
54 return y
56 class ANB:
57 bones = []
59 def __init__ (self, file):
60 def r32 (pos):
61 file.seek (pos)
62 buf = file.read (4)
63 return unpack ("<I", buf)[0]
65 hdrpos = r32 (19*4)
66 tmppos = r32 (0x50 + 3*4)
67 secpos = r32 (tmppos + 15*4)
69 file.seek (secpos)
70 data = file.read ()
72 def r32 (pos):
73 return unpack ("<I", data[pos:pos+4])[0]
74 def r16 (pos):
75 return unpack ("<H", data[pos:pos+2])[0]
76 def r8 (pos):
77 return unpack ("B", data[pos:pos+1])[0]
79 bonecount = r32 (hdrpos + 20)
81 tmp = r32 (hdrpos + 16)
82 offs = unpack ("<%dI" % bonecount, data[tmp:tmp + bonecount*4])
84 tmp = r32 (hdrpos + 8)
85 flags = unpack ("%dB" % bonecount, data[tmp:tmp + bonecount])
87 posecount = r16 (hdrpos + 4)
89 def rbone (index):
90 bonedata = data[offs[index]:]
92 flag = flags[index]
94 if flag == 0:
95 quaternion = unpack ("<4f", bonedata[:16])
96 bone = (quaternion, None)
98 elif flag == 12:
99 floats = unpack ("<6f", bonedata[:24])
100 offset = unpack ("<I", bonedata[24:28])[0]
101 subdata = data[offset:]
102 payload = map (lambda k: unpack ("<3H", subdata[k*6:(k+1)*6]),
103 range (posecount))
104 bone = (floats, payload)
106 elif flag == 13:
107 floats = unpack ("<5f", bonedata[:20])
108 offset = unpack ("<I", bonedata[20:24])[0]
109 subdata = data[offset:offset+posecount*2]
110 payload = unpack ("<%dH" % posecount, subdata)
111 bone = (floats, payload)
113 else: # 3,4,5,6
114 floats = unpack ("<8f", bonedata[:32])
115 offset = unpack ("<I", bonedata[32:36])[0]
116 subdata = data[offset:offset+posecount*4]
117 payload = unpack ("<%dI" % posecount, subdata)
118 bone = (floats, payload)
120 return (flag, bone)
122 self.bones = map (rbone, range (bonecount))
123 self.posecount = posecount
125 def zerotest (self, path):
126 for i, (flag, (floats, payload)) in enumerate (self.bones):
127 if flag in [3,4,5,6]:
128 global maxd, mind
130 for i in range (8):
131 if floats[i] > maxd[i][0]:
132 maxd[i] = (floats[i], path, i, flag)
133 if floats[i] < mind[i][0]:
134 mind[i] = (floats[i], path, i, flag)
136 def twentytest (self, path):
137 for i, (flag, (floats, payload)) in enumerate (self.bones):
138 if flag == 12:
139 global maxd, mind
141 for i in range (6):
142 if floats[i] > maxd[i][0]:
143 maxd[i] = (floats[i], path, i, flag)
144 if floats[i] < mind[i][0]:
145 mind[i] = (floats[i], path, i, flag)
147 def thirtytest (self, path):
148 for i, (flag, (floats, payload)) in enumerate (self.bones):
149 if flag == 13:
150 global maxd, mind
152 for i in range (5):
153 if floats[i] > maxd[i][0]:
154 maxd[i] = (floats[i], path, i, flag)
155 if floats[i] < mind[i][0]:
156 mind[i] = (floats[i], path, i, flag)
158 def showbone (self, index, bone, below):
159 (flag, (floats, payload)) = bone
160 print "[%2d] %d bone%d" % (index, flag, index)
161 for i, f in enumerate (floats):
162 print " (%d) % .13f (% e)" % (i, f, f)
164 if flag == 0:
165 print "magnitude %f" % magn (floats)
167 elif flag == 12:
168 print
169 for i, (x,y,z) in enumerate (payload):
170 print " (%3d) %04x %04x %04x" % (i, x, y, z)
172 elif flag == 13:
173 print "degrees1(?) % f" % (180.0 * floats[0] / math.pi)
174 print "degrees2(?) % f" % (180.0 * floats[1] / math.pi)
175 print "magnitude %f" % magn (floats[2:])
176 print
177 for i, h in enumerate (payload):
178 print " (%2d) %04x" % (i, h)
180 else: # 3,4,5,6
181 s1 = sum (floats[:4])
182 s2 = sum (floats[4:])
183 s3 = s1 + s2
184 # print "% .13f %e" % (magn (floats[3:6]), magn (floats[3:6]))
185 # print "% .13f % .13f % .13f\n% e, % e, % e" % (s1, s2, s3,
186 # s1, s2, s3)
187 print
188 lut = bitlut[flag - 3]
189 for i, d in enumerate (payload):
190 l = [((d >> b[0]) & ((1 << b[1]) - 1), b[1]) for b in lut]
191 (x,xl), (y,yl), (z,zl), (w,wl) = l
192 xs = bitstr (x, xl)
193 ys = bitstr (y, yl)
194 zs = bitstr (z, zl)
195 ws = bitstr (w, wl)
197 print " (%2d) %08x %s %s %s %s" % (i, d, xs, ys, zs, ws),
198 which = 1
199 if below:
200 print
201 print " "*14,
202 print "%*d %*d %*d %*d" % (xl, kalms (x, xl),
203 yl, kalms (y, yl),
204 zl, kalms (z, zl),
205 wl, kalms (w, wl))
206 elif which == 1:
207 print "% 4d % 4d % 4d % 4d" % (kalms (x, xl),
208 kalms (y, yl),
209 kalms (z, zl),
210 kalms (w, wl))
211 elif which == 2:
212 fl = map (lambda (v, l): fkalms (v, l), l)
213 fl[0] = fl[0] * floats[4] + floats[0]
214 fl[1] = fl[1] * floats[5] + floats[1]
215 fl[2] = fl[2] * floats[6] + floats[2]
216 fl[3] = fl[3] * floats[7] + floats[3]
217 print "% f % f % f % f (%f)" % (fl[0], fl[1], fl[2], fl[3],
218 magn (fl))
219 elif which == 0:
220 print
221 else:
222 print "% f % f % f % f" % (fkalms2 (x, xl, floats),
223 fkalms2 (y, yl, floats),
224 fkalms2 (z, zl, floats),
225 fkalms2 (w, wl, floats))
227 def show (self, below = False):
228 print "flags = %s" % str ([b[0] for b in self.bones])
229 print "poses = %d" % self.posecount
230 print
231 for index, bone in enumerate (self.bones):
232 self.showbone (index, bone, below)
233 print '-'*70
235 def main ():
236 def process (path):
237 print path
238 file = open (path, "rb")
239 anb = ANB (file)
240 # anb.zerotest (path)
241 # anb.twentytest (path)
242 anb.show ()
243 file.close ()
245 if len (sys.argv) < 2:
246 if sys.stdin.isatty ():
247 sys.stderr.write ("path please")
248 sys.exit (1)
249 else:
250 for line in sys.stdin:
251 path = line[:-1]
252 if True:
253 file = open (path, "rb")
254 anb = ANB (file)
255 # anb.zerotest (path)
256 anb.twentytest (path)
257 # anb.thirtytest (path)
258 file.close ()
259 else:
260 process (path)
261 else:
262 # shamelessly stolen from git
263 (r,w) = os.pipe ()
264 pid = os.fork ()
265 if pid == 0:
266 os.dup2 (w, 1)
267 os.dup2 (w, 2)
268 os.close (r)
269 os.close (w)
270 for path in sys.argv[1:]:
271 process (path)
272 return
274 os.dup2 (r, 0)
275 os.close (r)
276 os.close (w)
277 os.execl ("/bin/sh", "sh", "-c", os.getenv ("PAGER", default="less"))
279 if __name__ == "__main__":
280 main ()
281 def pr (i):
282 (v, path, index, flag) = maxd[i]
283 print "max %d: % f %s %d %d" % (i, v, path, index, flag)
285 (v, path, index, flag) = mind[i]
286 print "min %d: % f %s %d %d" % (i, v, path, index, flag)
288 for i in range (8):
289 pr (i)