pgtools 1.0.0

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.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +25 -0
  3. data/bin/bxm_decoder +2 -0
  4. data/bin/bxm_encoder +2 -0
  5. data/bin/clh_convert +2 -0
  6. data/bin/clp_convert +2 -0
  7. data/bin/clw_convert +2 -0
  8. data/bin/dat_creator +2 -0
  9. data/bin/dat_extractor +2 -0
  10. data/bin/dat_ls +2 -0
  11. data/bin/eff_idd_creator +2 -0
  12. data/bin/eff_idd_extractor +2 -0
  13. data/bin/exp_convert_wiiu_pc +2 -0
  14. data/bin/exp_tool +2 -0
  15. data/bin/mot_convert_wiiu_pc +2 -0
  16. data/bin/mot_tool +2 -0
  17. data/bin/pkz_extractor +2 -0
  18. data/bin/scr_creator +2 -0
  19. data/bin/scr_extractor +2 -0
  20. data/bin/wmb_cleanup +2 -0
  21. data/bin/wmb_common_bones +2 -0
  22. data/bin/wmb_convert_pc_switch +2 -0
  23. data/bin/wmb_convert_wiiu_pc +2 -0
  24. data/bin/wmb_export_assimp +2 -0
  25. data/bin/wmb_get_bone_map +2 -0
  26. data/bin/wmb_import_assimp +2 -0
  27. data/bin/wmb_import_nier +2 -0
  28. data/bin/wmb_import_wiiu +2 -0
  29. data/bin/wtb_convert_wiiu_pc +2 -0
  30. data/bin/wtx_creator +2 -0
  31. data/bin/wtx_extractor +2 -0
  32. data/lib/bayonetta/alignment.rb +14 -0
  33. data/lib/bayonetta/bone.rb +55 -0
  34. data/lib/bayonetta/bxm.rb +180 -0
  35. data/lib/bayonetta/clh.rb +159 -0
  36. data/lib/bayonetta/clp.rb +212 -0
  37. data/lib/bayonetta/clw.rb +166 -0
  38. data/lib/bayonetta/dat.rb +261 -0
  39. data/lib/bayonetta/eff.rb +314 -0
  40. data/lib/bayonetta/endianness.rb +53 -0
  41. data/lib/bayonetta/exp.rb +768 -0
  42. data/lib/bayonetta/linalg.rb +416 -0
  43. data/lib/bayonetta/material_database.yaml +2581 -0
  44. data/lib/bayonetta/mot.rb +763 -0
  45. data/lib/bayonetta/pkz.rb +63 -0
  46. data/lib/bayonetta/scr.rb +393 -0
  47. data/lib/bayonetta/tools/bxm_decoder.rb +23 -0
  48. data/lib/bayonetta/tools/bxm_encoder.rb +37 -0
  49. data/lib/bayonetta/tools/clh_convert.rb +60 -0
  50. data/lib/bayonetta/tools/clp_convert.rb +70 -0
  51. data/lib/bayonetta/tools/clw_convert.rb +60 -0
  52. data/lib/bayonetta/tools/dat_creator.rb +57 -0
  53. data/lib/bayonetta/tools/dat_extractor.rb +94 -0
  54. data/lib/bayonetta/tools/dat_ls.rb +106 -0
  55. data/lib/bayonetta/tools/eff_idd_creator.rb +66 -0
  56. data/lib/bayonetta/tools/eff_idd_extractor.rb +73 -0
  57. data/lib/bayonetta/tools/exp_convert_wiiu_pc.rb +33 -0
  58. data/lib/bayonetta/tools/exp_tool.rb +48 -0
  59. data/lib/bayonetta/tools/mot_convert_wiiu_pc.rb +33 -0
  60. data/lib/bayonetta/tools/mot_tool.rb +60 -0
  61. data/lib/bayonetta/tools/pkz_extractor.rb +75 -0
  62. data/lib/bayonetta/tools/scr_creator.rb +63 -0
  63. data/lib/bayonetta/tools/scr_extractor.rb +78 -0
  64. data/lib/bayonetta/tools/wmb_cleanup.rb +250 -0
  65. data/lib/bayonetta/tools/wmb_common_bones.rb +45 -0
  66. data/lib/bayonetta/tools/wmb_convert_pc_switch.rb +35 -0
  67. data/lib/bayonetta/tools/wmb_convert_wiiu_pc.rb +33 -0
  68. data/lib/bayonetta/tools/wmb_export_assimp.rb +479 -0
  69. data/lib/bayonetta/tools/wmb_get_bone_map.rb +50 -0
  70. data/lib/bayonetta/tools/wmb_import_assimp.rb +735 -0
  71. data/lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb +472 -0
  72. data/lib/bayonetta/tools/wmb_import_nier.rb +309 -0
  73. data/lib/bayonetta/tools/wtb_convert_wiiu_pc.rb +95 -0
  74. data/lib/bayonetta/tools/wtb_import_textures.rb +103 -0
  75. data/lib/bayonetta/tools/wtx_creator.rb +69 -0
  76. data/lib/bayonetta/tools/wtx_extractor.rb +85 -0
  77. data/lib/bayonetta/vertex_types.yaml +213 -0
  78. data/lib/bayonetta/vertex_types2.yaml +164 -0
  79. data/lib/bayonetta/vertex_types_nier.yaml +145 -0
  80. data/lib/bayonetta/wmb.rb +2443 -0
  81. data/lib/bayonetta/wmb3.rb +759 -0
  82. data/lib/bayonetta/wtb.rb +481 -0
  83. data/lib/bayonetta.rb +60 -0
  84. metadata +254 -0
@@ -0,0 +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