pgtools 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +25 -25
- data/bin/bxm_decoder +2 -2
- data/bin/bxm_encoder +2 -2
- data/bin/clh_convert +2 -2
- data/bin/clp_convert +2 -2
- data/bin/clw_convert +2 -2
- data/bin/dat_creator +2 -2
- data/bin/dat_extractor +2 -2
- data/bin/dat_ls +2 -2
- data/bin/eff_idd_creator +2 -2
- data/bin/eff_idd_extractor +2 -2
- data/bin/exp_convert_wiiu_pc +2 -2
- data/bin/exp_tool +2 -2
- data/bin/mot_convert_wiiu_pc +2 -2
- data/bin/mot_tool +2 -2
- data/bin/pkz_extractor +2 -2
- data/bin/scr_creator +2 -2
- data/bin/scr_extractor +2 -2
- data/bin/wmb_cleanup +2 -2
- data/bin/wmb_common_bones +2 -2
- data/bin/wmb_convert_pc_switch +2 -2
- data/bin/wmb_convert_wiiu_pc +2 -2
- data/bin/wmb_export_assimp +2 -2
- data/bin/wmb_get_bone_map +2 -2
- data/bin/wmb_import_assimp +2 -2
- data/bin/wmb_import_nier +2 -2
- data/bin/wmb_import_wiiu +2 -2
- data/bin/wtb_convert_wiiu_pc +2 -2
- data/bin/wtx_creator +2 -2
- data/bin/wtx_extractor +2 -2
- data/lib/bayonetta/alignment.rb +0 -0
- data/lib/bayonetta/bone.rb +0 -0
- data/lib/bayonetta/bxm.rb +180 -180
- data/lib/bayonetta/clh.rb +159 -159
- data/lib/bayonetta/clp.rb +212 -212
- data/lib/bayonetta/clw.rb +166 -166
- data/lib/bayonetta/dat.rb +261 -261
- data/lib/bayonetta/eff.rb +314 -314
- data/lib/bayonetta/endianness.rb +0 -0
- data/lib/bayonetta/exp.rb +768 -768
- data/lib/bayonetta/linalg.rb +416 -416
- data/lib/bayonetta/material_database.yaml +2581 -2581
- data/lib/bayonetta/mot.rb +763 -763
- data/lib/bayonetta/pkz.rb +63 -63
- data/lib/bayonetta/scr.rb +0 -0
- data/lib/bayonetta/tools/bxm_decoder.rb +23 -23
- data/lib/bayonetta/tools/bxm_encoder.rb +37 -37
- data/lib/bayonetta/tools/clh_convert.rb +60 -60
- data/lib/bayonetta/tools/clp_convert.rb +70 -70
- data/lib/bayonetta/tools/clw_convert.rb +60 -60
- data/lib/bayonetta/tools/dat_creator.rb +57 -57
- data/lib/bayonetta/tools/dat_extractor.rb +94 -94
- data/lib/bayonetta/tools/dat_ls.rb +106 -106
- data/lib/bayonetta/tools/eff_idd_creator.rb +66 -66
- data/lib/bayonetta/tools/eff_idd_extractor.rb +73 -73
- data/lib/bayonetta/tools/exp_convert_wiiu_pc.rb +33 -33
- data/lib/bayonetta/tools/exp_tool.rb +48 -48
- data/lib/bayonetta/tools/mot_convert_wiiu_pc.rb +33 -33
- data/lib/bayonetta/tools/mot_tool.rb +0 -0
- data/lib/bayonetta/tools/pkz_extractor.rb +75 -75
- data/lib/bayonetta/tools/scr_creator.rb +63 -63
- data/lib/bayonetta/tools/scr_extractor.rb +78 -78
- data/lib/bayonetta/tools/wmb_cleanup.rb +250 -250
- data/lib/bayonetta/tools/wmb_common_bones.rb +45 -45
- data/lib/bayonetta/tools/wmb_convert_pc_switch.rb +35 -35
- data/lib/bayonetta/tools/wmb_convert_wiiu_pc.rb +33 -33
- data/lib/bayonetta/tools/wmb_export_assimp.rb +479 -479
- data/lib/bayonetta/tools/wmb_get_bone_map.rb +50 -50
- data/lib/bayonetta/tools/wmb_import_assimp.rb +735 -735
- data/lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb +472 -472
- data/lib/bayonetta/tools/wmb_import_nier.rb +309 -309
- data/lib/bayonetta/tools/wtb_convert_wiiu_pc.rb +95 -95
- data/lib/bayonetta/tools/wtb_import_textures.rb +103 -103
- data/lib/bayonetta/tools/wtx_creator.rb +69 -69
- data/lib/bayonetta/tools/wtx_extractor.rb +85 -85
- data/lib/bayonetta/vertex_types.yaml +0 -0
- data/lib/bayonetta/vertex_types2.yaml +0 -0
- data/lib/bayonetta/vertex_types_nier.yaml +145 -145
- data/lib/bayonetta/wmb.rb +2455 -2443
- data/lib/bayonetta/wmb3.rb +759 -759
- data/lib/bayonetta/wtb.rb +481 -481
- data/lib/bayonetta.rb +60 -60
- metadata +2 -2
data/lib/bayonetta/mot.rb
CHANGED
@@ -1,763 +1,763 @@
|
|
1
|
-
module Bayonetta
|
2
|
-
|
3
|
-
module MOTRemaper
|
4
|
-
|
5
|
-
def remap_bones(map)
|
6
|
-
@records.each { |r|
|
7
|
-
if map[r.bone_index]
|
8
|
-
r.bone_index = map[r.bone_index]
|
9
|
-
end
|
10
|
-
}
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
module MOTDecoder
|
16
|
-
|
17
|
-
def decode_frame(frame_index)
|
18
|
-
raise "Invalid frame number #{frame_index} (#{0} - #{@header.frame_count}!" if frame_index < 0 || frame_index >= @header.frame_count
|
19
|
-
tracks = Hash::new { |h,k| h[k] = {} }
|
20
|
-
@records.each_with_index { |r, i|
|
21
|
-
if r.interpolation_type != -1
|
22
|
-
if r.interpolation_type == 0
|
23
|
-
tracks[r.bone_index][r.animation_track] = r.value
|
24
|
-
else
|
25
|
-
tracks[r.bone_index][r.animation_track] = @interpolations[i].value(frame_index)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
}
|
29
|
-
tracks
|
30
|
-
end
|
31
|
-
|
32
|
-
def decode
|
33
|
-
tracks = Hash::new { |h,k| h[k] = {} }
|
34
|
-
motion = {}
|
35
|
-
motion[:flag] = @header.flag
|
36
|
-
motion[:frame_count] = frame_count = @header.frame_count
|
37
|
-
motion[:tracks] = tracks
|
38
|
-
@records.each_with_index { |r, i|
|
39
|
-
if r.interpolation_type != -1
|
40
|
-
if r.interpolation_type == 0
|
41
|
-
tracks[r.bone_index][r.animation_track] = [r.value] * frame_count
|
42
|
-
else
|
43
|
-
tracks[r.bone_index][r.animation_track] = @interpolations[i].values(frame_count)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
}
|
47
|
-
motion
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
module QuantizedValues
|
53
|
-
def get_p(i)
|
54
|
-
@p + @keys[i].cp * @dp
|
55
|
-
end
|
56
|
-
|
57
|
-
def get_m1(i)
|
58
|
-
@m1 + @keys[i].cm1 * @dm1
|
59
|
-
end
|
60
|
-
|
61
|
-
def get_m0(i)
|
62
|
-
@m0 + @keys[i].cm0 * @dm0
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
module DirectValues
|
67
|
-
def get_p(i)
|
68
|
-
@keys[i].p
|
69
|
-
end
|
70
|
-
|
71
|
-
def get_m1(i)
|
72
|
-
@keys[i].m1
|
73
|
-
end
|
74
|
-
|
75
|
-
def get_m0(i)
|
76
|
-
@keys[i].m0
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
module AbsoluteIndexes
|
81
|
-
def key_frame_indexes
|
82
|
-
@keys.collect { |k| k.index }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
module RelativeIndexes
|
87
|
-
def key_frame_indexes
|
88
|
-
index = 0
|
89
|
-
@keys.collect { |k| index += k.index }
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
module KeyFrameInterpolate
|
94
|
-
def interpol(frame, start_index, stop_index, i)
|
95
|
-
p_0 = get_p(i)
|
96
|
-
p_1 = get_p(i+1)
|
97
|
-
m_0 = get_m1(i)
|
98
|
-
m_1 = get_m0(i+1)
|
99
|
-
t = (frame - start_index).to_f / (stop_index - start_index)
|
100
|
-
(2 * t*t*t - 3 * t*t + 1)*p_0 + (t*t*t - 2 * t*t + t)*m_0 + (-2 * t*t*t + 3 * t*t)*p_1 + (t*t*t - t * t)*m_1
|
101
|
-
end
|
102
|
-
|
103
|
-
def values(frame_count)
|
104
|
-
vs = [0.0]*frame_count
|
105
|
-
kfis = key_frame_indexes
|
106
|
-
kfis.each_cons(2).each_with_index { |(start_index, stop_index), i|
|
107
|
-
(start_index..stop_index).each { |frame|
|
108
|
-
vs[frame] = interpol(frame, start_index, stop_index, i)
|
109
|
-
}
|
110
|
-
}
|
111
|
-
(0...kfis.first).each { |i|
|
112
|
-
vs[i] = vs[kfis.first]
|
113
|
-
}
|
114
|
-
((kfis.last+1)...frame_count).each { |i|
|
115
|
-
vs[i] = vs[kfis.last]
|
116
|
-
}
|
117
|
-
vs
|
118
|
-
end
|
119
|
-
|
120
|
-
def value(frame_index)
|
121
|
-
kfis = key_frame_indexes
|
122
|
-
if frame_index <= kfis.first
|
123
|
-
return get_p(0)
|
124
|
-
elsif frame_index >= kfis.last
|
125
|
-
return get_p(kfis.length - 1)
|
126
|
-
else
|
127
|
-
kfis.each_cons(2).each_with_index { |(start_index, stop_index), i|
|
128
|
-
if frame_index <= stop_index && frame_index >= start_index
|
129
|
-
return interpol(frame_index, start_index, stop_index, i)
|
130
|
-
end
|
131
|
-
}
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
class MOT2File < LibBin::Structure
|
138
|
-
include MOTDecoder
|
139
|
-
include MOTRemaper
|
140
|
-
|
141
|
-
class Interpolation1 < LibBin::Structure
|
142
|
-
float :keys, count: '..\records[__index]\num_keys'
|
143
|
-
|
144
|
-
def values(frame_count)
|
145
|
-
count = frame_count
|
146
|
-
@keys + [@keys.last] * (count - keys.length)
|
147
|
-
end
|
148
|
-
|
149
|
-
def value(frame_index)
|
150
|
-
v = @keys[frame_index]
|
151
|
-
v = @keys.last unless v
|
152
|
-
v
|
153
|
-
end
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
class Interpolation2 < LibBin::Structure
|
158
|
-
float :p
|
159
|
-
float :dp
|
160
|
-
uint16 :keys, count: '..\records[__index]\num_keys'
|
161
|
-
|
162
|
-
def values(frame_count)
|
163
|
-
count = frame_count
|
164
|
-
res = @keys.collect { |k| @p + k*@dp }
|
165
|
-
res + [res.last] * (frame_count - keys.length)
|
166
|
-
end
|
167
|
-
|
168
|
-
def value(frame_index)
|
169
|
-
cp = @keys[frame_index]
|
170
|
-
cp = @keys.last unless cp
|
171
|
-
@p + cp*@dp
|
172
|
-
end
|
173
|
-
|
174
|
-
end
|
175
|
-
|
176
|
-
class Interpolation3 < LibBin::Structure
|
177
|
-
pghalf :p
|
178
|
-
pghalf :dp
|
179
|
-
uint8 :keys, count: '..\records[__index]\num_keys'
|
180
|
-
|
181
|
-
def values(frame_count)
|
182
|
-
count = frame_count
|
183
|
-
res = @keys.collect { |k| @p + k*@dp }
|
184
|
-
res + [res.last] * (frame_count - keys.length)
|
185
|
-
end
|
186
|
-
|
187
|
-
def value(frame_index)
|
188
|
-
cp = @keys[frame_index]
|
189
|
-
cp = @keys.last unless cp
|
190
|
-
@p + cp*@dp
|
191
|
-
end
|
192
|
-
|
193
|
-
end
|
194
|
-
|
195
|
-
class Key4 < LibBin::Structure
|
196
|
-
uint16 :index
|
197
|
-
uint16 :dummy
|
198
|
-
float :p
|
199
|
-
float :m0
|
200
|
-
float :m1
|
201
|
-
|
202
|
-
def __size
|
203
|
-
16
|
204
|
-
end
|
205
|
-
|
206
|
-
end
|
207
|
-
|
208
|
-
class Interpolation4 < LibBin::Structure
|
209
|
-
include DirectValues
|
210
|
-
include AbsoluteIndexes
|
211
|
-
include KeyFrameInterpolate
|
212
|
-
register_field :keys, Key4, count: '..\records[__index]\num_keys'
|
213
|
-
|
214
|
-
def __size
|
215
|
-
@keys.length * 16
|
216
|
-
end
|
217
|
-
|
218
|
-
end
|
219
|
-
|
220
|
-
class Key5 < LibBin::Structure
|
221
|
-
uint16 :index
|
222
|
-
uint16 :cp
|
223
|
-
uint16 :cm0
|
224
|
-
uint16 :cm1
|
225
|
-
end
|
226
|
-
|
227
|
-
class Interpolation5 < LibBin::Structure
|
228
|
-
include QuantizedValues
|
229
|
-
include AbsoluteIndexes
|
230
|
-
include KeyFrameInterpolate
|
231
|
-
float :p
|
232
|
-
float :dp
|
233
|
-
float :m0
|
234
|
-
float :dm0
|
235
|
-
float :m1
|
236
|
-
float :dm1
|
237
|
-
register_field :keys, Key5, count: '..\records[__index]\num_keys'
|
238
|
-
|
239
|
-
def __size
|
240
|
-
24 + @keys.length * 8
|
241
|
-
end
|
242
|
-
|
243
|
-
end
|
244
|
-
|
245
|
-
class Key6 < LibBin::Structure
|
246
|
-
uint8 :index
|
247
|
-
uint8 :cp
|
248
|
-
uint8 :cm0
|
249
|
-
uint8 :cm1
|
250
|
-
end
|
251
|
-
|
252
|
-
class Interpolation6 < LibBin::Structure
|
253
|
-
include QuantizedValues
|
254
|
-
include AbsoluteIndexes
|
255
|
-
include KeyFrameInterpolate
|
256
|
-
pghalf :p
|
257
|
-
pghalf :dp
|
258
|
-
pghalf :m0
|
259
|
-
pghalf :dm0
|
260
|
-
pghalf :m1
|
261
|
-
pghalf :dm1
|
262
|
-
register_field :keys, Key6, count: '..\records[__index]\num_keys'
|
263
|
-
|
264
|
-
def __size
|
265
|
-
12 + @keys.length * 4
|
266
|
-
end
|
267
|
-
|
268
|
-
end
|
269
|
-
|
270
|
-
class Key7 < LibBin::Structure
|
271
|
-
uint8 :index
|
272
|
-
uint8 :cp
|
273
|
-
uint8 :cm0
|
274
|
-
uint8 :cm1
|
275
|
-
end
|
276
|
-
|
277
|
-
class Interpolation7 < LibBin::Structure
|
278
|
-
include QuantizedValues
|
279
|
-
include RelativeIndexes
|
280
|
-
include KeyFrameInterpolate
|
281
|
-
pghalf :p
|
282
|
-
pghalf :dp
|
283
|
-
pghalf :m0
|
284
|
-
pghalf :dm0
|
285
|
-
pghalf :m1
|
286
|
-
pghalf :dm1
|
287
|
-
register_field :keys, Key7, count: '..\records[__index]\num_keys'
|
288
|
-
|
289
|
-
def __size
|
290
|
-
12 + @keys.length * 4
|
291
|
-
end
|
292
|
-
|
293
|
-
end
|
294
|
-
|
295
|
-
class Key8 < LibBin::Structure
|
296
|
-
uint8 :index_proxy, count: 2
|
297
|
-
uint8 :cp
|
298
|
-
uint8 :cm0
|
299
|
-
uint8 :cm1
|
300
|
-
def index
|
301
|
-
@index_proxy.pack("C2").unpack("S>").first
|
302
|
-
end
|
303
|
-
|
304
|
-
def index=(v)
|
305
|
-
@index_proxy = [v].pack("S>").unpack("C2")
|
306
|
-
v
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
class Interpolation8 < LibBin::Structure
|
311
|
-
include QuantizedValues
|
312
|
-
include AbsoluteIndexes
|
313
|
-
include KeyFrameInterpolate
|
314
|
-
pghalf :p
|
315
|
-
pghalf :dp
|
316
|
-
pghalf :m0
|
317
|
-
pghalf :dm0
|
318
|
-
pghalf :m1
|
319
|
-
pghalf :dm1
|
320
|
-
register_field :keys, Key8, count: '..\records[__index]\num_keys'
|
321
|
-
|
322
|
-
def __size
|
323
|
-
12 + @keys.length * 4
|
324
|
-
end
|
325
|
-
|
326
|
-
end
|
327
|
-
|
328
|
-
class Record < LibBin::Structure
|
329
|
-
int16 :bone_index
|
330
|
-
int8 :animation_track
|
331
|
-
int8 :interpolation_type
|
332
|
-
int16 :num_keys
|
333
|
-
int16 :u_a
|
334
|
-
uint32 :offset
|
335
|
-
|
336
|
-
def value
|
337
|
-
raise "Only animation track 1 have a value" unless @interpolation_type == 0
|
338
|
-
[@offset].pack("L").unpack("F").first
|
339
|
-
end
|
340
|
-
|
341
|
-
def __size
|
342
|
-
12
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
class Header < LibBin::Structure
|
347
|
-
string :id, 4
|
348
|
-
uint32 :version
|
349
|
-
uint16 :flag
|
350
|
-
uint16 :frame_count
|
351
|
-
uint32 :offset_records
|
352
|
-
uint32 :num_records
|
353
|
-
int8 :u_a, count: 4
|
354
|
-
string :name, 16
|
355
|
-
end
|
356
|
-
|
357
|
-
register_field :header, Header
|
358
|
-
register_field :records, Record, count: 'header\num_records', offset: 'header\offset_records'
|
359
|
-
register_field :terminator, Record, offset: 'header\offset_records + 12*header\num_records'
|
360
|
-
register_field :interpolations,
|
361
|
-
'interpolation_type_selector(records[__iterator]\interpolation_type)',
|
362
|
-
count: 'header\num_records', sequence: true,
|
363
|
-
offset: 'records[__iterator]\offset + header\offset_records + 12*__iterator',
|
364
|
-
condition: 'records[__iterator]\interpolation_type != 0 && records[__iterator]\interpolation_type != -1'
|
365
|
-
|
366
|
-
def interpolation_type_selector(interpolation_type)
|
367
|
-
interpolation = nil
|
368
|
-
case interpolation_type
|
369
|
-
when 1
|
370
|
-
interpolation = Interpolation1
|
371
|
-
when 2
|
372
|
-
interpolation = Interpolation2
|
373
|
-
when 3
|
374
|
-
interpolation = Interpolation3
|
375
|
-
when 4
|
376
|
-
interpolation = Interpolation4
|
377
|
-
when 5
|
378
|
-
interpolation = Interpolation5
|
379
|
-
when 6
|
380
|
-
interpolation = Interpolation6
|
381
|
-
when 7
|
382
|
-
interpolation = Interpolation7
|
383
|
-
when 8
|
384
|
-
interpolation = Interpolation8
|
385
|
-
when -1, 0
|
386
|
-
interpolation = nil
|
387
|
-
else
|
388
|
-
raise "Unknown interpolation type: #{interpolation_type}, please report!"
|
389
|
-
end
|
390
|
-
interpolation
|
391
|
-
end
|
392
|
-
|
393
|
-
def self.is_bayo2?(f)
|
394
|
-
f.rewind
|
395
|
-
id = f.read(4)
|
396
|
-
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
397
|
-
uint = "L"
|
398
|
-
version = f.read(4).unpack(uint).first
|
399
|
-
f.rewind
|
400
|
-
return true if version == 0x20120405 || version == 0x05041220
|
401
|
-
return false
|
402
|
-
end
|
403
|
-
|
404
|
-
def self.is_big?(f)
|
405
|
-
f.rewind
|
406
|
-
block = lambda { |int|
|
407
|
-
id = f.read(4)
|
408
|
-
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
409
|
-
f.read(4).unpack(int).first == 0x20120405
|
410
|
-
}
|
411
|
-
big = block.call("l>")
|
412
|
-
f.rewind
|
413
|
-
small = block.call("l<")
|
414
|
-
f.rewind
|
415
|
-
raise "Invalid data!" unless big ^ small
|
416
|
-
return big
|
417
|
-
end
|
418
|
-
|
419
|
-
def self.convert(input_name, output_name, input_big = true, output_big = false)
|
420
|
-
input = File.open(input_name, "rb")
|
421
|
-
id = input.read(4).unpack("a4").first
|
422
|
-
raise "Invalid file type #{id}!" unless id == "mot\0".b
|
423
|
-
output = File.open(output_name, "wb")
|
424
|
-
output.write("\x00"*input.size)
|
425
|
-
input.seek(0);
|
426
|
-
output.seek(0);
|
427
|
-
|
428
|
-
unless is_bayo2?(input)
|
429
|
-
mot = MOTFile::new
|
430
|
-
else
|
431
|
-
mot = self::new
|
432
|
-
end
|
433
|
-
mot.__convert(input, output, input_big, output_big)
|
434
|
-
|
435
|
-
input.close
|
436
|
-
output.close
|
437
|
-
end
|
438
|
-
|
439
|
-
def self.load(input_name)
|
440
|
-
if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
441
|
-
input = input_name
|
442
|
-
else
|
443
|
-
input = File.open(input_name, "rb")
|
444
|
-
end
|
445
|
-
|
446
|
-
unless is_bayo2?(input)
|
447
|
-
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
448
|
-
return MOTFile::load(input_name)
|
449
|
-
end
|
450
|
-
|
451
|
-
input_big = is_big?(input)
|
452
|
-
|
453
|
-
mot = self::new
|
454
|
-
mot.instance_variable_set(:@__was_big, input_big)
|
455
|
-
mot.__load(input, input_big)
|
456
|
-
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
457
|
-
|
458
|
-
mot
|
459
|
-
end
|
460
|
-
|
461
|
-
def dump(output_name, output_big = false)
|
462
|
-
if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
463
|
-
output = output_name
|
464
|
-
else
|
465
|
-
output = File.open(output_name, "wb")
|
466
|
-
end
|
467
|
-
output.rewind
|
468
|
-
|
469
|
-
__set_dump_state(output, output_big, nil, nil)
|
470
|
-
__dump_fields
|
471
|
-
__unset_dump_state
|
472
|
-
sz = output.size
|
473
|
-
sz = align(sz, 0x4)
|
474
|
-
if sz > output.size
|
475
|
-
output.seek(sz-1)
|
476
|
-
output.write("\x00")
|
477
|
-
end
|
478
|
-
|
479
|
-
output.close unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
480
|
-
self
|
481
|
-
end
|
482
|
-
|
483
|
-
def was_big?
|
484
|
-
@__was_big
|
485
|
-
end
|
486
|
-
|
487
|
-
end
|
488
|
-
|
489
|
-
class MOTFile < LibBin::Structure
|
490
|
-
include MOTDecoder
|
491
|
-
include MOTRemaper
|
492
|
-
|
493
|
-
class Interpolation1 < LibBin::Structure
|
494
|
-
float :keys, count: '..\records[__index]\num_keys'
|
495
|
-
|
496
|
-
def values(frame_count)
|
497
|
-
count = frame_count
|
498
|
-
@keys + [@keys.last] * (count - keys.length)
|
499
|
-
end
|
500
|
-
|
501
|
-
def value(frame_index)
|
502
|
-
v = @keys[frame_index]
|
503
|
-
v = @keys.last unless v
|
504
|
-
v
|
505
|
-
end
|
506
|
-
|
507
|
-
end
|
508
|
-
|
509
|
-
class Key4 < LibBin::Structure
|
510
|
-
uint16 :index
|
511
|
-
uint16 :cp
|
512
|
-
uint16 :cm0
|
513
|
-
uint16 :cm1
|
514
|
-
|
515
|
-
def initialize
|
516
|
-
@index = 0
|
517
|
-
@cp = 0
|
518
|
-
@cm0 = 0
|
519
|
-
@cm1 = 0
|
520
|
-
end
|
521
|
-
|
522
|
-
end
|
523
|
-
|
524
|
-
class Interpolation4 < LibBin::Structure
|
525
|
-
include QuantizedValues
|
526
|
-
include AbsoluteIndexes
|
527
|
-
include KeyFrameInterpolate
|
528
|
-
float :p
|
529
|
-
float :dp
|
530
|
-
float :m0
|
531
|
-
float :dm0
|
532
|
-
float :m1
|
533
|
-
float :dm1
|
534
|
-
register_field :keys, Key4, count: '..\records[__index]\num_keys'
|
535
|
-
|
536
|
-
def __size
|
537
|
-
24 + @keys.length*8
|
538
|
-
end
|
539
|
-
|
540
|
-
end
|
541
|
-
|
542
|
-
class Key6 < LibBin::Structure
|
543
|
-
uint8 :index
|
544
|
-
uint8 :cp
|
545
|
-
uint8 :cm0
|
546
|
-
uint8 :cm1
|
547
|
-
|
548
|
-
def initialize
|
549
|
-
@index = 0
|
550
|
-
@cp = 0
|
551
|
-
@cm0 = 0
|
552
|
-
@cm1 = 0
|
553
|
-
end
|
554
|
-
|
555
|
-
def __size
|
556
|
-
4
|
557
|
-
end
|
558
|
-
|
559
|
-
end
|
560
|
-
|
561
|
-
class Interpolation6 < LibBin::Structure
|
562
|
-
include QuantizedValues
|
563
|
-
include RelativeIndexes
|
564
|
-
include KeyFrameInterpolate
|
565
|
-
pghalf :p
|
566
|
-
pghalf :dp
|
567
|
-
pghalf :m0
|
568
|
-
pghalf :dm0
|
569
|
-
pghalf :m1
|
570
|
-
pghalf :dm1
|
571
|
-
register_field :keys, Key6, count: '..\records[__index]\num_keys'
|
572
|
-
|
573
|
-
def __size
|
574
|
-
12 + @keys.length*4
|
575
|
-
end
|
576
|
-
|
577
|
-
end
|
578
|
-
|
579
|
-
class Key7 < LibBin::Structure
|
580
|
-
uint16 :index
|
581
|
-
uint8 :dummy
|
582
|
-
uint8 :cp
|
583
|
-
uint8 :cm0
|
584
|
-
uint8 :cm1
|
585
|
-
|
586
|
-
def initialize
|
587
|
-
@index = 0
|
588
|
-
@dummy = 0
|
589
|
-
@cp = 0
|
590
|
-
@cm0 = 0
|
591
|
-
@cm1 = 0
|
592
|
-
end
|
593
|
-
|
594
|
-
def __size
|
595
|
-
6
|
596
|
-
end
|
597
|
-
|
598
|
-
end
|
599
|
-
|
600
|
-
class Interpolation7 < LibBin::Structure
|
601
|
-
include QuantizedValues
|
602
|
-
include AbsoluteIndexes
|
603
|
-
include KeyFrameInterpolate
|
604
|
-
pghalf :p
|
605
|
-
pghalf :dp
|
606
|
-
pghalf :m0
|
607
|
-
pghalf :dm0
|
608
|
-
pghalf :m1
|
609
|
-
pghalf :dm1
|
610
|
-
register_field :keys, Key7, count: '..\records[__index]\num_keys'
|
611
|
-
|
612
|
-
def __size
|
613
|
-
12 + @keys.length * 6
|
614
|
-
end
|
615
|
-
|
616
|
-
end
|
617
|
-
|
618
|
-
class Record < LibBin::Structure
|
619
|
-
int16 :bone_index
|
620
|
-
int8 :animation_track
|
621
|
-
int8 :interpolation_type
|
622
|
-
int16 :num_keys
|
623
|
-
int16 :u_a
|
624
|
-
uint32 :offset
|
625
|
-
|
626
|
-
def value
|
627
|
-
raise "Only animation track 1 have a value" unless @interpolation_type == 0
|
628
|
-
[@offset].pack("L").unpack("F").first
|
629
|
-
end
|
630
|
-
|
631
|
-
def __size
|
632
|
-
12
|
633
|
-
end
|
634
|
-
end
|
635
|
-
|
636
|
-
class Header < LibBin::Structure
|
637
|
-
string :id, 4
|
638
|
-
uint16 :flag
|
639
|
-
uint16 :frame_count
|
640
|
-
uint32 :offset_records
|
641
|
-
uint32 :num_records
|
642
|
-
end
|
643
|
-
|
644
|
-
register_field :header, Header
|
645
|
-
register_field :records, Record, count: 'header\num_records', offset: 'header\offset_records'
|
646
|
-
register_field :interpolations,
|
647
|
-
'interpolation_type_selector(records[__iterator]\interpolation_type)',
|
648
|
-
count: 'header\num_records',
|
649
|
-
sequence: true,
|
650
|
-
offset: 'records[__iterator]\offset',
|
651
|
-
condition: 'records[__iterator]\interpolation_type != 0'
|
652
|
-
|
653
|
-
def interpolation_type_selector(interpolation_type)
|
654
|
-
interpolation = nil
|
655
|
-
case interpolation_type
|
656
|
-
when 1
|
657
|
-
interpolation = Interpolation1
|
658
|
-
when 4
|
659
|
-
interpolation = Interpolation4
|
660
|
-
when 6
|
661
|
-
interpolation = Interpolation6
|
662
|
-
when 7
|
663
|
-
interpolation = Interpolation7
|
664
|
-
when -1, 0
|
665
|
-
interpolation = nil
|
666
|
-
else
|
667
|
-
raise "Unknown interpolation type: #{interpolation_type}, please report!"
|
668
|
-
end
|
669
|
-
end
|
670
|
-
|
671
|
-
def self.is_bayo2?(f)
|
672
|
-
f.rewind
|
673
|
-
id = f.read(4)
|
674
|
-
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
675
|
-
uint = "L"
|
676
|
-
version = f.read(4).unpack(uint).first
|
677
|
-
f.rewind
|
678
|
-
return true if version == 0x20120405 || version == 0x05041220
|
679
|
-
return false
|
680
|
-
end
|
681
|
-
|
682
|
-
def self.is_big?(f)
|
683
|
-
f.rewind
|
684
|
-
block = lambda { |int|
|
685
|
-
id = f.read(4)
|
686
|
-
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
687
|
-
f.read(4)
|
688
|
-
offset_records = f.read(4).unpack(int).first
|
689
|
-
num_records = f.read(4).unpack(int).first
|
690
|
-
num_records >= 0 && num_records*12 < f.size && offset_records > 0 && offset_records < f.size
|
691
|
-
}
|
692
|
-
big = block.call("l>")
|
693
|
-
f.rewind
|
694
|
-
small = block.call("l<")
|
695
|
-
f.rewind
|
696
|
-
raise "Invalid data!" unless big ^ small
|
697
|
-
return big
|
698
|
-
end
|
699
|
-
|
700
|
-
def self.convert(input_name, output_name, input_big = true, output_big = false)
|
701
|
-
input = File.open(input_name, "rb")
|
702
|
-
id = input.read(4).unpack("a4").first
|
703
|
-
raise "Invalid file type #{id}!" unless id == "mot\0".b
|
704
|
-
output = File.open(output_name, "wb")
|
705
|
-
output.write("\x00"*input.size)
|
706
|
-
input.seek(0);
|
707
|
-
output.seek(0);
|
708
|
-
|
709
|
-
if is_bayo2?(input)
|
710
|
-
mot = MOT2File::new
|
711
|
-
else
|
712
|
-
mot = self::new
|
713
|
-
end
|
714
|
-
mot.__convert(input, output, input_big, output_big)
|
715
|
-
|
716
|
-
input.close
|
717
|
-
output.close
|
718
|
-
end
|
719
|
-
|
720
|
-
def self.load(input_name)
|
721
|
-
if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
722
|
-
input = input_name
|
723
|
-
else
|
724
|
-
input = File.open(input_name, "rb")
|
725
|
-
end
|
726
|
-
|
727
|
-
if is_bayo2?(input)
|
728
|
-
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
729
|
-
return MOT2File::load(input_name)
|
730
|
-
end
|
731
|
-
|
732
|
-
input_big = is_big?(input)
|
733
|
-
|
734
|
-
mot = self::new
|
735
|
-
mot.instance_variable_set(:@__was_big, input_big)
|
736
|
-
mot.__load(input, input_big)
|
737
|
-
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
738
|
-
|
739
|
-
mot
|
740
|
-
end
|
741
|
-
|
742
|
-
def was_big?
|
743
|
-
@__was_big
|
744
|
-
end
|
745
|
-
|
746
|
-
def dump(output_name, output_big = false)
|
747
|
-
if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
748
|
-
output = output_name
|
749
|
-
else
|
750
|
-
output = File.open(output_name, "wb")
|
751
|
-
end
|
752
|
-
output.rewind
|
753
|
-
|
754
|
-
__set_dump_state(output, output_big, nil, nil)
|
755
|
-
__dump_fields
|
756
|
-
__unset_dump_state
|
757
|
-
output.close unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
758
|
-
self
|
759
|
-
end
|
760
|
-
|
761
|
-
end
|
762
|
-
|
763
|
-
end
|
1
|
+
module Bayonetta
|
2
|
+
|
3
|
+
module MOTRemaper
|
4
|
+
|
5
|
+
def remap_bones(map)
|
6
|
+
@records.each { |r|
|
7
|
+
if map[r.bone_index]
|
8
|
+
r.bone_index = map[r.bone_index]
|
9
|
+
end
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
module MOTDecoder
|
16
|
+
|
17
|
+
def decode_frame(frame_index)
|
18
|
+
raise "Invalid frame number #{frame_index} (#{0} - #{@header.frame_count}!" if frame_index < 0 || frame_index >= @header.frame_count
|
19
|
+
tracks = Hash::new { |h,k| h[k] = {} }
|
20
|
+
@records.each_with_index { |r, i|
|
21
|
+
if r.interpolation_type != -1
|
22
|
+
if r.interpolation_type == 0
|
23
|
+
tracks[r.bone_index][r.animation_track] = r.value
|
24
|
+
else
|
25
|
+
tracks[r.bone_index][r.animation_track] = @interpolations[i].value(frame_index)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
}
|
29
|
+
tracks
|
30
|
+
end
|
31
|
+
|
32
|
+
def decode
|
33
|
+
tracks = Hash::new { |h,k| h[k] = {} }
|
34
|
+
motion = {}
|
35
|
+
motion[:flag] = @header.flag
|
36
|
+
motion[:frame_count] = frame_count = @header.frame_count
|
37
|
+
motion[:tracks] = tracks
|
38
|
+
@records.each_with_index { |r, i|
|
39
|
+
if r.interpolation_type != -1
|
40
|
+
if r.interpolation_type == 0
|
41
|
+
tracks[r.bone_index][r.animation_track] = [r.value] * frame_count
|
42
|
+
else
|
43
|
+
tracks[r.bone_index][r.animation_track] = @interpolations[i].values(frame_count)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
}
|
47
|
+
motion
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
module QuantizedValues
|
53
|
+
def get_p(i)
|
54
|
+
@p + @keys[i].cp * @dp
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_m1(i)
|
58
|
+
@m1 + @keys[i].cm1 * @dm1
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_m0(i)
|
62
|
+
@m0 + @keys[i].cm0 * @dm0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module DirectValues
|
67
|
+
def get_p(i)
|
68
|
+
@keys[i].p
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_m1(i)
|
72
|
+
@keys[i].m1
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_m0(i)
|
76
|
+
@keys[i].m0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
module AbsoluteIndexes
|
81
|
+
def key_frame_indexes
|
82
|
+
@keys.collect { |k| k.index }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module RelativeIndexes
|
87
|
+
def key_frame_indexes
|
88
|
+
index = 0
|
89
|
+
@keys.collect { |k| index += k.index }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module KeyFrameInterpolate
|
94
|
+
def interpol(frame, start_index, stop_index, i)
|
95
|
+
p_0 = get_p(i)
|
96
|
+
p_1 = get_p(i+1)
|
97
|
+
m_0 = get_m1(i)
|
98
|
+
m_1 = get_m0(i+1)
|
99
|
+
t = (frame - start_index).to_f / (stop_index - start_index)
|
100
|
+
(2 * t*t*t - 3 * t*t + 1)*p_0 + (t*t*t - 2 * t*t + t)*m_0 + (-2 * t*t*t + 3 * t*t)*p_1 + (t*t*t - t * t)*m_1
|
101
|
+
end
|
102
|
+
|
103
|
+
def values(frame_count)
|
104
|
+
vs = [0.0]*frame_count
|
105
|
+
kfis = key_frame_indexes
|
106
|
+
kfis.each_cons(2).each_with_index { |(start_index, stop_index), i|
|
107
|
+
(start_index..stop_index).each { |frame|
|
108
|
+
vs[frame] = interpol(frame, start_index, stop_index, i)
|
109
|
+
}
|
110
|
+
}
|
111
|
+
(0...kfis.first).each { |i|
|
112
|
+
vs[i] = vs[kfis.first]
|
113
|
+
}
|
114
|
+
((kfis.last+1)...frame_count).each { |i|
|
115
|
+
vs[i] = vs[kfis.last]
|
116
|
+
}
|
117
|
+
vs
|
118
|
+
end
|
119
|
+
|
120
|
+
def value(frame_index)
|
121
|
+
kfis = key_frame_indexes
|
122
|
+
if frame_index <= kfis.first
|
123
|
+
return get_p(0)
|
124
|
+
elsif frame_index >= kfis.last
|
125
|
+
return get_p(kfis.length - 1)
|
126
|
+
else
|
127
|
+
kfis.each_cons(2).each_with_index { |(start_index, stop_index), i|
|
128
|
+
if frame_index <= stop_index && frame_index >= start_index
|
129
|
+
return interpol(frame_index, start_index, stop_index, i)
|
130
|
+
end
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
class MOT2File < LibBin::Structure
|
138
|
+
include MOTDecoder
|
139
|
+
include MOTRemaper
|
140
|
+
|
141
|
+
class Interpolation1 < LibBin::Structure
|
142
|
+
float :keys, count: '..\records[__index]\num_keys'
|
143
|
+
|
144
|
+
def values(frame_count)
|
145
|
+
count = frame_count
|
146
|
+
@keys + [@keys.last] * (count - keys.length)
|
147
|
+
end
|
148
|
+
|
149
|
+
def value(frame_index)
|
150
|
+
v = @keys[frame_index]
|
151
|
+
v = @keys.last unless v
|
152
|
+
v
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
class Interpolation2 < LibBin::Structure
|
158
|
+
float :p
|
159
|
+
float :dp
|
160
|
+
uint16 :keys, count: '..\records[__index]\num_keys'
|
161
|
+
|
162
|
+
def values(frame_count)
|
163
|
+
count = frame_count
|
164
|
+
res = @keys.collect { |k| @p + k*@dp }
|
165
|
+
res + [res.last] * (frame_count - keys.length)
|
166
|
+
end
|
167
|
+
|
168
|
+
def value(frame_index)
|
169
|
+
cp = @keys[frame_index]
|
170
|
+
cp = @keys.last unless cp
|
171
|
+
@p + cp*@dp
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
class Interpolation3 < LibBin::Structure
|
177
|
+
pghalf :p
|
178
|
+
pghalf :dp
|
179
|
+
uint8 :keys, count: '..\records[__index]\num_keys'
|
180
|
+
|
181
|
+
def values(frame_count)
|
182
|
+
count = frame_count
|
183
|
+
res = @keys.collect { |k| @p + k*@dp }
|
184
|
+
res + [res.last] * (frame_count - keys.length)
|
185
|
+
end
|
186
|
+
|
187
|
+
def value(frame_index)
|
188
|
+
cp = @keys[frame_index]
|
189
|
+
cp = @keys.last unless cp
|
190
|
+
@p + cp*@dp
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
class Key4 < LibBin::Structure
|
196
|
+
uint16 :index
|
197
|
+
uint16 :dummy
|
198
|
+
float :p
|
199
|
+
float :m0
|
200
|
+
float :m1
|
201
|
+
|
202
|
+
def __size
|
203
|
+
16
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
class Interpolation4 < LibBin::Structure
|
209
|
+
include DirectValues
|
210
|
+
include AbsoluteIndexes
|
211
|
+
include KeyFrameInterpolate
|
212
|
+
register_field :keys, Key4, count: '..\records[__index]\num_keys'
|
213
|
+
|
214
|
+
def __size
|
215
|
+
@keys.length * 16
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
class Key5 < LibBin::Structure
|
221
|
+
uint16 :index
|
222
|
+
uint16 :cp
|
223
|
+
uint16 :cm0
|
224
|
+
uint16 :cm1
|
225
|
+
end
|
226
|
+
|
227
|
+
class Interpolation5 < LibBin::Structure
|
228
|
+
include QuantizedValues
|
229
|
+
include AbsoluteIndexes
|
230
|
+
include KeyFrameInterpolate
|
231
|
+
float :p
|
232
|
+
float :dp
|
233
|
+
float :m0
|
234
|
+
float :dm0
|
235
|
+
float :m1
|
236
|
+
float :dm1
|
237
|
+
register_field :keys, Key5, count: '..\records[__index]\num_keys'
|
238
|
+
|
239
|
+
def __size
|
240
|
+
24 + @keys.length * 8
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
class Key6 < LibBin::Structure
|
246
|
+
uint8 :index
|
247
|
+
uint8 :cp
|
248
|
+
uint8 :cm0
|
249
|
+
uint8 :cm1
|
250
|
+
end
|
251
|
+
|
252
|
+
class Interpolation6 < LibBin::Structure
|
253
|
+
include QuantizedValues
|
254
|
+
include AbsoluteIndexes
|
255
|
+
include KeyFrameInterpolate
|
256
|
+
pghalf :p
|
257
|
+
pghalf :dp
|
258
|
+
pghalf :m0
|
259
|
+
pghalf :dm0
|
260
|
+
pghalf :m1
|
261
|
+
pghalf :dm1
|
262
|
+
register_field :keys, Key6, count: '..\records[__index]\num_keys'
|
263
|
+
|
264
|
+
def __size
|
265
|
+
12 + @keys.length * 4
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
class Key7 < LibBin::Structure
|
271
|
+
uint8 :index
|
272
|
+
uint8 :cp
|
273
|
+
uint8 :cm0
|
274
|
+
uint8 :cm1
|
275
|
+
end
|
276
|
+
|
277
|
+
class Interpolation7 < LibBin::Structure
|
278
|
+
include QuantizedValues
|
279
|
+
include RelativeIndexes
|
280
|
+
include KeyFrameInterpolate
|
281
|
+
pghalf :p
|
282
|
+
pghalf :dp
|
283
|
+
pghalf :m0
|
284
|
+
pghalf :dm0
|
285
|
+
pghalf :m1
|
286
|
+
pghalf :dm1
|
287
|
+
register_field :keys, Key7, count: '..\records[__index]\num_keys'
|
288
|
+
|
289
|
+
def __size
|
290
|
+
12 + @keys.length * 4
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
class Key8 < LibBin::Structure
|
296
|
+
uint8 :index_proxy, count: 2
|
297
|
+
uint8 :cp
|
298
|
+
uint8 :cm0
|
299
|
+
uint8 :cm1
|
300
|
+
def index
|
301
|
+
@index_proxy.pack("C2").unpack("S>").first
|
302
|
+
end
|
303
|
+
|
304
|
+
def index=(v)
|
305
|
+
@index_proxy = [v].pack("S>").unpack("C2")
|
306
|
+
v
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
class Interpolation8 < LibBin::Structure
|
311
|
+
include QuantizedValues
|
312
|
+
include AbsoluteIndexes
|
313
|
+
include KeyFrameInterpolate
|
314
|
+
pghalf :p
|
315
|
+
pghalf :dp
|
316
|
+
pghalf :m0
|
317
|
+
pghalf :dm0
|
318
|
+
pghalf :m1
|
319
|
+
pghalf :dm1
|
320
|
+
register_field :keys, Key8, count: '..\records[__index]\num_keys'
|
321
|
+
|
322
|
+
def __size
|
323
|
+
12 + @keys.length * 4
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
327
|
+
|
328
|
+
class Record < LibBin::Structure
|
329
|
+
int16 :bone_index
|
330
|
+
int8 :animation_track
|
331
|
+
int8 :interpolation_type
|
332
|
+
int16 :num_keys
|
333
|
+
int16 :u_a
|
334
|
+
uint32 :offset
|
335
|
+
|
336
|
+
def value
|
337
|
+
raise "Only animation track 1 have a value" unless @interpolation_type == 0
|
338
|
+
[@offset].pack("L").unpack("F").first
|
339
|
+
end
|
340
|
+
|
341
|
+
def __size
|
342
|
+
12
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
class Header < LibBin::Structure
|
347
|
+
string :id, 4
|
348
|
+
uint32 :version
|
349
|
+
uint16 :flag
|
350
|
+
uint16 :frame_count
|
351
|
+
uint32 :offset_records
|
352
|
+
uint32 :num_records
|
353
|
+
int8 :u_a, count: 4
|
354
|
+
string :name, 16
|
355
|
+
end
|
356
|
+
|
357
|
+
register_field :header, Header
|
358
|
+
register_field :records, Record, count: 'header\num_records', offset: 'header\offset_records'
|
359
|
+
register_field :terminator, Record, offset: 'header\offset_records + 12*header\num_records'
|
360
|
+
register_field :interpolations,
|
361
|
+
'interpolation_type_selector(records[__iterator]\interpolation_type)',
|
362
|
+
count: 'header\num_records', sequence: true,
|
363
|
+
offset: 'records[__iterator]\offset + header\offset_records + 12*__iterator',
|
364
|
+
condition: 'records[__iterator]\interpolation_type != 0 && records[__iterator]\interpolation_type != -1'
|
365
|
+
|
366
|
+
def interpolation_type_selector(interpolation_type)
|
367
|
+
interpolation = nil
|
368
|
+
case interpolation_type
|
369
|
+
when 1
|
370
|
+
interpolation = Interpolation1
|
371
|
+
when 2
|
372
|
+
interpolation = Interpolation2
|
373
|
+
when 3
|
374
|
+
interpolation = Interpolation3
|
375
|
+
when 4
|
376
|
+
interpolation = Interpolation4
|
377
|
+
when 5
|
378
|
+
interpolation = Interpolation5
|
379
|
+
when 6
|
380
|
+
interpolation = Interpolation6
|
381
|
+
when 7
|
382
|
+
interpolation = Interpolation7
|
383
|
+
when 8
|
384
|
+
interpolation = Interpolation8
|
385
|
+
when -1, 0
|
386
|
+
interpolation = nil
|
387
|
+
else
|
388
|
+
raise "Unknown interpolation type: #{interpolation_type}, please report!"
|
389
|
+
end
|
390
|
+
interpolation
|
391
|
+
end
|
392
|
+
|
393
|
+
def self.is_bayo2?(f)
|
394
|
+
f.rewind
|
395
|
+
id = f.read(4)
|
396
|
+
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
397
|
+
uint = "L"
|
398
|
+
version = f.read(4).unpack(uint).first
|
399
|
+
f.rewind
|
400
|
+
return true if version == 0x20120405 || version == 0x05041220
|
401
|
+
return false
|
402
|
+
end
|
403
|
+
|
404
|
+
def self.is_big?(f)
|
405
|
+
f.rewind
|
406
|
+
block = lambda { |int|
|
407
|
+
id = f.read(4)
|
408
|
+
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
409
|
+
f.read(4).unpack(int).first == 0x20120405
|
410
|
+
}
|
411
|
+
big = block.call("l>")
|
412
|
+
f.rewind
|
413
|
+
small = block.call("l<")
|
414
|
+
f.rewind
|
415
|
+
raise "Invalid data!" unless big ^ small
|
416
|
+
return big
|
417
|
+
end
|
418
|
+
|
419
|
+
def self.convert(input_name, output_name, input_big = true, output_big = false)
|
420
|
+
input = File.open(input_name, "rb")
|
421
|
+
id = input.read(4).unpack("a4").first
|
422
|
+
raise "Invalid file type #{id}!" unless id == "mot\0".b
|
423
|
+
output = File.open(output_name, "wb")
|
424
|
+
output.write("\x00"*input.size)
|
425
|
+
input.seek(0);
|
426
|
+
output.seek(0);
|
427
|
+
|
428
|
+
unless is_bayo2?(input)
|
429
|
+
mot = MOTFile::new
|
430
|
+
else
|
431
|
+
mot = self::new
|
432
|
+
end
|
433
|
+
mot.__convert(input, output, input_big, output_big)
|
434
|
+
|
435
|
+
input.close
|
436
|
+
output.close
|
437
|
+
end
|
438
|
+
|
439
|
+
def self.load(input_name)
|
440
|
+
if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
441
|
+
input = input_name
|
442
|
+
else
|
443
|
+
input = File.open(input_name, "rb")
|
444
|
+
end
|
445
|
+
|
446
|
+
unless is_bayo2?(input)
|
447
|
+
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
448
|
+
return MOTFile::load(input_name)
|
449
|
+
end
|
450
|
+
|
451
|
+
input_big = is_big?(input)
|
452
|
+
|
453
|
+
mot = self::new
|
454
|
+
mot.instance_variable_set(:@__was_big, input_big)
|
455
|
+
mot.__load(input, input_big)
|
456
|
+
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
457
|
+
|
458
|
+
mot
|
459
|
+
end
|
460
|
+
|
461
|
+
def dump(output_name, output_big = false)
|
462
|
+
if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
463
|
+
output = output_name
|
464
|
+
else
|
465
|
+
output = File.open(output_name, "wb")
|
466
|
+
end
|
467
|
+
output.rewind
|
468
|
+
|
469
|
+
__set_dump_state(output, output_big, nil, nil)
|
470
|
+
__dump_fields
|
471
|
+
__unset_dump_state
|
472
|
+
sz = output.size
|
473
|
+
sz = align(sz, 0x4)
|
474
|
+
if sz > output.size
|
475
|
+
output.seek(sz-1)
|
476
|
+
output.write("\x00")
|
477
|
+
end
|
478
|
+
|
479
|
+
output.close unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
480
|
+
self
|
481
|
+
end
|
482
|
+
|
483
|
+
def was_big?
|
484
|
+
@__was_big
|
485
|
+
end
|
486
|
+
|
487
|
+
end
|
488
|
+
|
489
|
+
class MOTFile < LibBin::Structure
|
490
|
+
include MOTDecoder
|
491
|
+
include MOTRemaper
|
492
|
+
|
493
|
+
class Interpolation1 < LibBin::Structure
|
494
|
+
float :keys, count: '..\records[__index]\num_keys'
|
495
|
+
|
496
|
+
def values(frame_count)
|
497
|
+
count = frame_count
|
498
|
+
@keys + [@keys.last] * (count - keys.length)
|
499
|
+
end
|
500
|
+
|
501
|
+
def value(frame_index)
|
502
|
+
v = @keys[frame_index]
|
503
|
+
v = @keys.last unless v
|
504
|
+
v
|
505
|
+
end
|
506
|
+
|
507
|
+
end
|
508
|
+
|
509
|
+
class Key4 < LibBin::Structure
|
510
|
+
uint16 :index
|
511
|
+
uint16 :cp
|
512
|
+
uint16 :cm0
|
513
|
+
uint16 :cm1
|
514
|
+
|
515
|
+
def initialize
|
516
|
+
@index = 0
|
517
|
+
@cp = 0
|
518
|
+
@cm0 = 0
|
519
|
+
@cm1 = 0
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
523
|
+
|
524
|
+
class Interpolation4 < LibBin::Structure
|
525
|
+
include QuantizedValues
|
526
|
+
include AbsoluteIndexes
|
527
|
+
include KeyFrameInterpolate
|
528
|
+
float :p
|
529
|
+
float :dp
|
530
|
+
float :m0
|
531
|
+
float :dm0
|
532
|
+
float :m1
|
533
|
+
float :dm1
|
534
|
+
register_field :keys, Key4, count: '..\records[__index]\num_keys'
|
535
|
+
|
536
|
+
def __size
|
537
|
+
24 + @keys.length*8
|
538
|
+
end
|
539
|
+
|
540
|
+
end
|
541
|
+
|
542
|
+
class Key6 < LibBin::Structure
|
543
|
+
uint8 :index
|
544
|
+
uint8 :cp
|
545
|
+
uint8 :cm0
|
546
|
+
uint8 :cm1
|
547
|
+
|
548
|
+
def initialize
|
549
|
+
@index = 0
|
550
|
+
@cp = 0
|
551
|
+
@cm0 = 0
|
552
|
+
@cm1 = 0
|
553
|
+
end
|
554
|
+
|
555
|
+
def __size
|
556
|
+
4
|
557
|
+
end
|
558
|
+
|
559
|
+
end
|
560
|
+
|
561
|
+
class Interpolation6 < LibBin::Structure
|
562
|
+
include QuantizedValues
|
563
|
+
include RelativeIndexes
|
564
|
+
include KeyFrameInterpolate
|
565
|
+
pghalf :p
|
566
|
+
pghalf :dp
|
567
|
+
pghalf :m0
|
568
|
+
pghalf :dm0
|
569
|
+
pghalf :m1
|
570
|
+
pghalf :dm1
|
571
|
+
register_field :keys, Key6, count: '..\records[__index]\num_keys'
|
572
|
+
|
573
|
+
def __size
|
574
|
+
12 + @keys.length*4
|
575
|
+
end
|
576
|
+
|
577
|
+
end
|
578
|
+
|
579
|
+
class Key7 < LibBin::Structure
|
580
|
+
uint16 :index
|
581
|
+
uint8 :dummy
|
582
|
+
uint8 :cp
|
583
|
+
uint8 :cm0
|
584
|
+
uint8 :cm1
|
585
|
+
|
586
|
+
def initialize
|
587
|
+
@index = 0
|
588
|
+
@dummy = 0
|
589
|
+
@cp = 0
|
590
|
+
@cm0 = 0
|
591
|
+
@cm1 = 0
|
592
|
+
end
|
593
|
+
|
594
|
+
def __size
|
595
|
+
6
|
596
|
+
end
|
597
|
+
|
598
|
+
end
|
599
|
+
|
600
|
+
class Interpolation7 < LibBin::Structure
|
601
|
+
include QuantizedValues
|
602
|
+
include AbsoluteIndexes
|
603
|
+
include KeyFrameInterpolate
|
604
|
+
pghalf :p
|
605
|
+
pghalf :dp
|
606
|
+
pghalf :m0
|
607
|
+
pghalf :dm0
|
608
|
+
pghalf :m1
|
609
|
+
pghalf :dm1
|
610
|
+
register_field :keys, Key7, count: '..\records[__index]\num_keys'
|
611
|
+
|
612
|
+
def __size
|
613
|
+
12 + @keys.length * 6
|
614
|
+
end
|
615
|
+
|
616
|
+
end
|
617
|
+
|
618
|
+
class Record < LibBin::Structure
|
619
|
+
int16 :bone_index
|
620
|
+
int8 :animation_track
|
621
|
+
int8 :interpolation_type
|
622
|
+
int16 :num_keys
|
623
|
+
int16 :u_a
|
624
|
+
uint32 :offset
|
625
|
+
|
626
|
+
def value
|
627
|
+
raise "Only animation track 1 have a value" unless @interpolation_type == 0
|
628
|
+
[@offset].pack("L").unpack("F").first
|
629
|
+
end
|
630
|
+
|
631
|
+
def __size
|
632
|
+
12
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
class Header < LibBin::Structure
|
637
|
+
string :id, 4
|
638
|
+
uint16 :flag
|
639
|
+
uint16 :frame_count
|
640
|
+
uint32 :offset_records
|
641
|
+
uint32 :num_records
|
642
|
+
end
|
643
|
+
|
644
|
+
register_field :header, Header
|
645
|
+
register_field :records, Record, count: 'header\num_records', offset: 'header\offset_records'
|
646
|
+
register_field :interpolations,
|
647
|
+
'interpolation_type_selector(records[__iterator]\interpolation_type)',
|
648
|
+
count: 'header\num_records',
|
649
|
+
sequence: true,
|
650
|
+
offset: 'records[__iterator]\offset',
|
651
|
+
condition: 'records[__iterator]\interpolation_type != 0'
|
652
|
+
|
653
|
+
def interpolation_type_selector(interpolation_type)
|
654
|
+
interpolation = nil
|
655
|
+
case interpolation_type
|
656
|
+
when 1
|
657
|
+
interpolation = Interpolation1
|
658
|
+
when 4
|
659
|
+
interpolation = Interpolation4
|
660
|
+
when 6
|
661
|
+
interpolation = Interpolation6
|
662
|
+
when 7
|
663
|
+
interpolation = Interpolation7
|
664
|
+
when -1, 0
|
665
|
+
interpolation = nil
|
666
|
+
else
|
667
|
+
raise "Unknown interpolation type: #{interpolation_type}, please report!"
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
def self.is_bayo2?(f)
|
672
|
+
f.rewind
|
673
|
+
id = f.read(4)
|
674
|
+
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
675
|
+
uint = "L"
|
676
|
+
version = f.read(4).unpack(uint).first
|
677
|
+
f.rewind
|
678
|
+
return true if version == 0x20120405 || version == 0x05041220
|
679
|
+
return false
|
680
|
+
end
|
681
|
+
|
682
|
+
def self.is_big?(f)
|
683
|
+
f.rewind
|
684
|
+
block = lambda { |int|
|
685
|
+
id = f.read(4)
|
686
|
+
raise "Invalid id #{id.inspect}!" if id != "mot\0".b
|
687
|
+
f.read(4)
|
688
|
+
offset_records = f.read(4).unpack(int).first
|
689
|
+
num_records = f.read(4).unpack(int).first
|
690
|
+
num_records >= 0 && num_records*12 < f.size && offset_records > 0 && offset_records < f.size
|
691
|
+
}
|
692
|
+
big = block.call("l>")
|
693
|
+
f.rewind
|
694
|
+
small = block.call("l<")
|
695
|
+
f.rewind
|
696
|
+
raise "Invalid data!" unless big ^ small
|
697
|
+
return big
|
698
|
+
end
|
699
|
+
|
700
|
+
def self.convert(input_name, output_name, input_big = true, output_big = false)
|
701
|
+
input = File.open(input_name, "rb")
|
702
|
+
id = input.read(4).unpack("a4").first
|
703
|
+
raise "Invalid file type #{id}!" unless id == "mot\0".b
|
704
|
+
output = File.open(output_name, "wb")
|
705
|
+
output.write("\x00"*input.size)
|
706
|
+
input.seek(0);
|
707
|
+
output.seek(0);
|
708
|
+
|
709
|
+
if is_bayo2?(input)
|
710
|
+
mot = MOT2File::new
|
711
|
+
else
|
712
|
+
mot = self::new
|
713
|
+
end
|
714
|
+
mot.__convert(input, output, input_big, output_big)
|
715
|
+
|
716
|
+
input.close
|
717
|
+
output.close
|
718
|
+
end
|
719
|
+
|
720
|
+
def self.load(input_name)
|
721
|
+
if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
722
|
+
input = input_name
|
723
|
+
else
|
724
|
+
input = File.open(input_name, "rb")
|
725
|
+
end
|
726
|
+
|
727
|
+
if is_bayo2?(input)
|
728
|
+
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
729
|
+
return MOT2File::load(input_name)
|
730
|
+
end
|
731
|
+
|
732
|
+
input_big = is_big?(input)
|
733
|
+
|
734
|
+
mot = self::new
|
735
|
+
mot.instance_variable_set(:@__was_big, input_big)
|
736
|
+
mot.__load(input, input_big)
|
737
|
+
input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
|
738
|
+
|
739
|
+
mot
|
740
|
+
end
|
741
|
+
|
742
|
+
def was_big?
|
743
|
+
@__was_big
|
744
|
+
end
|
745
|
+
|
746
|
+
def dump(output_name, output_big = false)
|
747
|
+
if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
748
|
+
output = output_name
|
749
|
+
else
|
750
|
+
output = File.open(output_name, "wb")
|
751
|
+
end
|
752
|
+
output.rewind
|
753
|
+
|
754
|
+
__set_dump_state(output, output_big, nil, nil)
|
755
|
+
__dump_fields
|
756
|
+
__unset_dump_state
|
757
|
+
output.close unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
|
758
|
+
self
|
759
|
+
end
|
760
|
+
|
761
|
+
end
|
762
|
+
|
763
|
+
end
|