pgtools 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,768 @@
1
+ module Bayonetta
2
+
3
+ module ExpQuantizedValues
4
+ def get_p(i)
5
+ @p + @keys[i].cp * @dp
6
+ end
7
+
8
+ def get_m1(i)
9
+ @m1 + @keys[i].cm1 * @dm1
10
+ end
11
+
12
+ def get_m0(i)
13
+ @m0 + @keys[i].cm0 * @dm0
14
+ end
15
+ end
16
+
17
+ module ExpDirectValues
18
+ def get_p(i)
19
+ @keys[i].p
20
+ end
21
+
22
+ def get_m1(i)
23
+ @keys[i].m1
24
+ end
25
+
26
+ def get_m0(i)
27
+ @keys[i].m0
28
+ end
29
+ end
30
+
31
+ module ExpAbsolutePositions
32
+ def key_positions
33
+ @key_positions ||= @keys.collect { |k| k.v }
34
+ end
35
+ end
36
+
37
+ module ExpRelativePositions
38
+ def key_positions
39
+ @key_positions ||= begin
40
+ sum = 0
41
+ @keys.collect { |k| sum += k.v }
42
+ end
43
+ end
44
+ end
45
+
46
+ module ExpKeyInterpolate
47
+ def interpol(position, start, stop, key_index)
48
+ p_0 = get_p(key_index)
49
+ p_1 = get_p(key_index + 1)
50
+ m_0 = get_m1(key_index)
51
+ m_1 = get_m0(key_index + 1)
52
+ t = (value - start).to_f / (stop - start)
53
+ t3 = t*t*t
54
+ t2 = t*t
55
+ (2 * t3 - 3 * t2 + 1)*p_0 + (t3 - 2 * t2 + t)*m_0 + (-2 * t3 + 3 * t2)*p_1 + (t3 - t2)*m_1
56
+ end
57
+
58
+ def interpolate(position)
59
+ if positions <= key_positions.first
60
+ get_p(0)
61
+ elsif positions >= key_positions.last
62
+ get_p(key_positions.length -1)
63
+ else
64
+ key_positions.each_cons(2).each_with_index { |(start, stop), i|
65
+ if position <= stop && position >= start
66
+ return interpol(position, start, stop)
67
+ end
68
+ }
69
+ end
70
+ end
71
+ end
72
+
73
+ class EXPFile2 < LibBin::Structure
74
+
75
+ class EXPFileHeader < LibBin::Structure
76
+ int8 :id, count: 4
77
+ int32 :version
78
+ uint32 :offset_records
79
+ uint32 :num_records
80
+ uint32 :offset_interpolations
81
+ uint32 :num_interpolations
82
+
83
+ def initialize
84
+ @id = "exp\0".b
85
+ @version = 0x20110714
86
+ @offset_records = 0
87
+ @num_records = 0
88
+ @offset_interpolations = 0
89
+ @num_interpolations = 0
90
+ end
91
+ end
92
+
93
+ class Record < LibBin::Structure
94
+ int16 :bone_index
95
+ int8 :animation_track
96
+ int8 :padding
97
+ int16 :num_operations
98
+ int16 :unknown
99
+ uint32 :offset
100
+
101
+ def initialize
102
+ @bone_index = 0
103
+ @animation_track = 0
104
+ @padding = 0
105
+ @num_operations = 0
106
+ @unknown = 0
107
+ @offset = 0
108
+ end
109
+
110
+ end
111
+
112
+ class Operation < LibBin::Structure
113
+ int8 :type
114
+ int8 :info
115
+ int16 :number
116
+ float :value
117
+
118
+ def initialize
119
+ @type = 0
120
+ @info = 0
121
+ @number = 0
122
+ @value = 0.0
123
+ end
124
+
125
+ end
126
+
127
+ class Entry < LibBin::Structure
128
+ register_field :operations, Operation, count: '..\records[__index]\num_operations'
129
+
130
+ def initialize
131
+ @operations = []
132
+ end
133
+
134
+ def abs(v)
135
+ v.abs
136
+ end
137
+
138
+ def get_value(tracks, table, interpolation_entries)
139
+ s = ""
140
+ @operations.each { |o|
141
+ case o.type
142
+ when 0
143
+ nil
144
+ when 1
145
+ s << "("
146
+ when 2
147
+ s << ")"
148
+ when 3
149
+ s << "tracks[table[#{o.number}]][#{o.info}]"
150
+ when 4
151
+ s << "#{o.value}"
152
+ when 5
153
+ case o.number
154
+ when 0
155
+ s << " + "
156
+ when 2
157
+ s << " * "
158
+ else
159
+ raise "Unknown arithmetic operation: #{o.number}!"
160
+ end
161
+ when 6
162
+ raise "Unknown function argument number: #{o.info}!" if o.info != 1
163
+ case o.number
164
+ when 1
165
+ s << "abs("
166
+ else
167
+ raise "Unknown function: #{o.number}!"
168
+ end
169
+ when 7
170
+ s << ")"
171
+ when 8
172
+ s << "interpolation_entries[#{o.number}].get_value("
173
+ else
174
+ raise "Unknown operation: #{o.type}!"
175
+ end
176
+ }
177
+ eval s
178
+ end
179
+
180
+ end
181
+
182
+ class Interpolation < LibBin::Structure
183
+ int16 :num_points
184
+ int16 :padding
185
+ uint32 :offset
186
+
187
+ def initialize
188
+ @num_points = 0
189
+ @padding = 0
190
+ @offset = 0
191
+ end
192
+
193
+ end
194
+
195
+ class Point < LibBin::Structure
196
+ float :v
197
+ float :p
198
+ float :m0
199
+ float :m1
200
+
201
+ def initialize
202
+ @v = 0.0
203
+ @p = 0.0
204
+ @m0 = 0.0
205
+ @m1 = 0.0
206
+ end
207
+
208
+ end
209
+
210
+ class InterpolationEntry < LibBin::Structure
211
+ register_field :points, Point, count: '..\interpolations[__index]\num_points'
212
+
213
+ def get_value(val)
214
+ @points.each_cons(2) { |left, right|
215
+ if left.v <= val && right.v >= val
216
+ p0 = left.p
217
+ p1 = right.p
218
+ m0 = left.m1
219
+ m1 = right.m0
220
+ t = (val - left.v).to_f / (right.v - left.v)
221
+ return (2 * t*t*t - 3 * t*t + 1)*p0 + (t*t*t - 2 * t*t + t)*m0 + (-2 * t*t*t + 3 * t*t)*p1 + (t*t*t - t * t)*m1
222
+ end
223
+
224
+ }
225
+ return 0.0
226
+ end
227
+
228
+ end
229
+
230
+ register_field :header, EXPFileHeader
231
+ register_field :records, Record, count: 'header\num_records', offset: 'header\offset_records'
232
+ register_field :entries, Entry, count: 'header\num_records', sequence: true,
233
+ offset: 'records[__iterator]\offset + header\offset_records + 12*__iterator'
234
+ register_field :interpolations, Interpolation, count: 'header\num_interpolations', offset: 'header\offset_interpolations'
235
+ register_field :interpolation_entries, InterpolationEntry, count: 'header\num_interpolations', sequence: true,
236
+ offset: 'interpolations[__iterator]\offset + header\offset_interpolations + 8*__iterator'
237
+
238
+ def apply(tracks, table)
239
+ rad_to_deg = 180.0 / Math::PI
240
+ deg_to_rad = Math::PI / 180.0
241
+ tracks.each { |tr|
242
+ tr[0] *= 10.0
243
+ tr[1] *= 10.0
244
+ tr[2] *= 10.0
245
+ tr[3] *= rad_to_deg
246
+ tr[4] *= rad_to_deg
247
+ tr[5] *= rad_to_deg
248
+ }
249
+ @records.each_with_index { |r, i|
250
+ bone_index = table[r.bone_index]
251
+ next unless bone_index
252
+ animation_track = r.animation_track
253
+ if @entries[i]
254
+ value = @entries[i].get_value(tracks, table, interpolation_entries)
255
+ end
256
+ tracks[bone_index][animation_track] = value
257
+ }
258
+ tracks.each { |tr|
259
+ tr[0] *= 0.1
260
+ tr[1] *= 0.1
261
+ tr[2] *= 0.1
262
+ tr[3] *= deg_to_rad
263
+ tr[4] *= deg_to_rad
264
+ tr[5] *= deg_to_rad
265
+ }
266
+ end
267
+
268
+ def recompute_layout
269
+ self
270
+ end
271
+
272
+ def was_big?
273
+ @__was_big
274
+ end
275
+
276
+ def dump(output_name, output_big = false)
277
+ if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
278
+ output = output_name
279
+ else
280
+ output = File.open(output_name, "wb")
281
+ end
282
+ output.rewind
283
+
284
+ __set_dump_state(output, output_big, nil, nil)
285
+ __dump_fields
286
+ __unset_dump_state
287
+ output.close unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
288
+ self
289
+ end
290
+
291
+ end
292
+
293
+ class EXPFile < LibBin::Structure
294
+
295
+ class EXPFileHeader < LibBin::Structure
296
+ int8 :id, count: 4
297
+ int32 :version
298
+ uint32 :offset_records
299
+ uint32 :num_records
300
+
301
+ def initialize
302
+ @id = "exp\0".b
303
+ @version = 0
304
+ @offset_records = 0
305
+ @num_records = 0
306
+ end
307
+
308
+ end
309
+
310
+ class Record < LibBin::Structure
311
+ int16 :u_a
312
+ int16 :bone_index
313
+ int8 :animation_track
314
+ int8 :entry_type
315
+ int8 :u_b
316
+ int8 :interpolation_type
317
+ int16 :num_points
318
+ int16 :u_c
319
+ uint32 :offset
320
+ uint32 :offset_interpolation
321
+
322
+ def initialize
323
+ @u_a = 0
324
+ @bone_index = 0
325
+ @animation_track = 0
326
+ @entry_type = 0
327
+ @u_b = 0
328
+ @interpolation_type = 0
329
+ @num_points = 0
330
+ @offset = 0
331
+ @offset_interpolation = 0
332
+ end
333
+
334
+ end
335
+
336
+ class Operation < LibBin::Structure
337
+ uint32 :flags
338
+ float :value
339
+
340
+ def initialize
341
+ @flags = 0
342
+ @value = 0.0
343
+ end
344
+
345
+ def transform_value( v )
346
+ if @flags == 0x4
347
+ v *= @value
348
+ elsif @flags == 0x20004
349
+ v = v.abs * @value
350
+ elsif @flags == 0x1
351
+ v += @value
352
+ else
353
+ raise "Unknown operation #{ "%x" % @flags }, please report!"
354
+ end
355
+ v
356
+ end
357
+
358
+ end
359
+
360
+ class Entry1 < LibBin::Structure
361
+ uint32 :flags
362
+ int16 :bone_index
363
+ int8 :animation_track
364
+ int8 :padding
365
+
366
+ def initialize
367
+ @flags = 0x80000001
368
+ @bone_index = 0
369
+ @animation_track = 0
370
+ @padding = 0
371
+ end
372
+
373
+ def get_value(pose, table)
374
+ pose[table[@bone_index]][@animation_track]
375
+ end
376
+
377
+ end
378
+
379
+ class Entry2 < LibBin::Structure
380
+ uint32 :flags
381
+ int16 :bone_index
382
+ int8 :animation_track
383
+ int8 :padding
384
+ register_field :operation, Operation
385
+
386
+ def initialize
387
+ @flags = 0x80000001
388
+ @bone_index = 0
389
+ @animation_track = 0
390
+ @padding = 0
391
+ @operation = Operation::new
392
+ end
393
+
394
+ def get_value(pose, table)
395
+ @operation.transform_value( pose[table[@bone_index]][@animation_track] )
396
+ end
397
+
398
+ end
399
+
400
+ class Entry3 < LibBin::Structure
401
+ uint32 :flags
402
+ int16 :bone_index
403
+ int8 :animation_track
404
+ int8 :padding
405
+ register_field :operations, Operation, count: 2
406
+
407
+ def initialize
408
+ @flags = 0x80000001
409
+ @bone_index = 0
410
+ @animation_track = 0
411
+ @padding = 0
412
+ @operations = [Operation::new, Operation::new]
413
+ end
414
+
415
+ def get_value(pose, table)
416
+ v = @operations[0].transform_value( pose[table[@bone_index]][@animation_track] )
417
+ v = @operations[1].transform_value( v )
418
+ end
419
+
420
+ end
421
+
422
+ class Entry < LibBin::Structure
423
+
424
+ def self.convert(input, output, input_big, output_big, parent, index, length = nil)
425
+ entry_type = parent.records[index].entry_type
426
+ entry = nil
427
+ case entry_type
428
+ when 1
429
+ entry = Entry1::convert(input, output, input_big, output_big, parent, index, length)
430
+ when 2
431
+ entry = Entry2::convert(input, output, input_big, output_big, parent, index, length)
432
+ when 3
433
+ entry = Entry3::convert(input, output, input_big, output_big, parent, index, length)
434
+ end
435
+ entry
436
+ end
437
+
438
+ def self.load(input, input_big, parent, index, length = nil)
439
+ entry_type = parent.records[index].entry_type
440
+ entry = nil
441
+ case entry_type
442
+ when 1
443
+ entry = Entry1::load(input, input_big, parent, index, length)
444
+ when 2
445
+ entry = Entry2::load(input, input_big, parent, index, length)
446
+ when 3
447
+ entry = Entry3::load(input, input_big, parent, index, length)
448
+ end
449
+ entry
450
+ end
451
+
452
+ end
453
+
454
+ class Key2 < LibBin::Structure
455
+ float :v
456
+ float :p
457
+ float :m0
458
+ float :m1
459
+
460
+ def initialize
461
+ @v = 0.0
462
+ @p = 0.0
463
+ @m0 = 0.0
464
+ @m1 = 0.0
465
+ end
466
+
467
+ def size
468
+ 3 * 4
469
+ end
470
+ end
471
+
472
+ class Interpolation2 < LibBin::Structure
473
+ include ExpDirectValues
474
+ include ExpAbsolutePositions
475
+ include ExpKeyInterpolate
476
+ register_field :keys, Key2, count: '..\records[__index]\num_points'
477
+
478
+ def size
479
+ @keys.collect(&:size).reduce(:+)
480
+ end
481
+ end
482
+
483
+ class Key4 < LibBin::Structure
484
+ float :v
485
+ uint16 :dummy
486
+ uint16 :cp
487
+ uint16 :cm0
488
+ uint16 :cm1
489
+
490
+ def initialize
491
+ @v = 0.0
492
+ @dummy = 0
493
+ @cp = 0
494
+ @cm0 = 0
495
+ @cm1 = 0
496
+ end
497
+
498
+ def size
499
+ 3 * 4
500
+ end
501
+ end
502
+
503
+ class Interpolation4 < LibBin::Structure
504
+ include ExpQuantizedValues
505
+ include ExpAbsolutePositions
506
+ include ExpKeyInterpolate
507
+ float :p
508
+ float :dp
509
+ float :m0
510
+ float :dm0
511
+ float :m1
512
+ float :dm1
513
+ register_field :keys, Key4, count: '..\records[__index]\num_points'
514
+
515
+ def size
516
+ 4 * 6 + @keys.collect(&:size).reduce(:+)
517
+ end
518
+ end
519
+
520
+ class Key6 < LibBin::Structure
521
+ uint8 :v
522
+ uint8 :cp
523
+ uint8 :cm0
524
+ uint8 :cm1
525
+
526
+ def initialize
527
+ @v = 0
528
+ @cp = 0
529
+ @cm0 = 0
530
+ @cm1 = 0
531
+ end
532
+
533
+ def size
534
+ 4
535
+ end
536
+ end
537
+
538
+ class Interpolation6 < LibBin::Structure
539
+ include ExpQuantizedValues
540
+ include ExpRelativePositions
541
+ include ExpKeyInterpolate
542
+ pghalf :p
543
+ pghalf :dp
544
+ pghalf :m0
545
+ pghalf :dm0
546
+ pghalf :m1
547
+ pghalf :dm1
548
+ register_field :keys, Key6, count: '..\records[__index]\num_points'
549
+
550
+ def size
551
+ 2 * 6 + @keys.collect(&:size).reduce(:+)
552
+ end
553
+ end
554
+
555
+ class Interpolation < LibBin::Structure
556
+
557
+ def self.convert(input, output, input_big, output_big, parent, index, length = nil)
558
+ case parent.records[index].interpolation_type
559
+ when 2
560
+ Interpolation2::convert(input, output, input_big, output_big, parent, index, length)
561
+ when 4
562
+ Interpolation4::convert(input, output, input_big, output_big, parent, index, length)
563
+ when 6
564
+ Interpolation6::convert(input, output, input_big, output_big, parent, index, length)
565
+ when -1
566
+ nil
567
+ else
568
+ raise "Unknown Interpolation type: #{interpolation_type}, please report!"
569
+ end
570
+ end
571
+
572
+ def self.load(input, input_big, parent, index, length = nil)
573
+ case parent.records[index].interpolation_type
574
+ when 2
575
+ Interpolation2::load(input, input_big, parent, index, length)
576
+ when 4
577
+ Interpolation4::load(input, input_big, parent, index, length)
578
+ when 6
579
+ Interpolation6::load(input, input_big, parent, index, length)
580
+ when -1
581
+ nil
582
+ else
583
+ raise "Unknown Interpolation type: #{interpolation_type}, please report!"
584
+ end
585
+ end
586
+
587
+ end
588
+
589
+ register_field :header, EXPFileHeader
590
+ register_field :records, Record, count: 'header\num_records', offset: 'header\offset_records'
591
+ register_field :entries, Entry, count: 'header\num_records', sequence: true,
592
+ offset: 'records[__iterator]\offset'
593
+ register_field :interpolations, Interpolation, count: 'header\num_records', sequence: true,
594
+ offset: 'records[__iterator]\offset_interpolation'
595
+
596
+ def was_big?
597
+ @__was_big
598
+ end
599
+
600
+ def apply(tracks, table)
601
+ rad_to_deg = 180.0 / Math::PI
602
+ deg_to_rad = Math::PI / 180.0
603
+ tracks.each { |tr|
604
+ tr[3] *= rad_to_deg
605
+ tr[4] *= rad_to_deg
606
+ tr[5] *= rad_to_deg
607
+ }
608
+ @records.each_with_index { |r, i|
609
+ bone_index = table[r.bone_index]
610
+ next unless bone_index
611
+ animation_track = r.animation_track
612
+ if @entries[i]
613
+ value = @entries[i].get_value(tracks, table)
614
+ end
615
+ if @interpolations[i]
616
+ value = @interpolations[i].interpolate(value)
617
+ end
618
+ tracks[bone_index][animation_track] = value
619
+ }
620
+ tracks.each { |tr|
621
+ tr[3] *= deg_to_rad
622
+ tr[4] *= deg_to_rad
623
+ tr[5] *= deg_to_rad
624
+ }
625
+ end
626
+
627
+ def add_entries(hash)
628
+ hash.each { |k, v|
629
+ raise "Invalid entry type #{k}!" if k>3 || k<1
630
+ v.times {
631
+ r = Record::new
632
+ r.entry_type = k
633
+ r.u_c = -1
634
+ @records.insert(-2, r)
635
+ case k
636
+ when 1
637
+ entry = Entry1::new
638
+ when 2
639
+ entry = Entry2::new
640
+ when 3
641
+ entry = Entry3::new
642
+ end
643
+ @entries.insert(-2, entry)
644
+ }
645
+ }
646
+ self
647
+ end
648
+
649
+ def recompute_layout
650
+ @header.num_records = @records.length
651
+ last_offset = @header.offset_records
652
+ last_offset += @records.collect(&:__size).reduce(:+)
653
+
654
+ table = @records.zip(@entries).to_h
655
+ reverse_table = table.invert
656
+ interpolation_table = @records.zip(@interpolations).to_h
657
+ reverse_interpolation_table = interpolation_table.invert
658
+
659
+ @records.sort_by! { |r| [r.bone_index, r.animation_track] }
660
+ @entries.sort_by! { |e| e ? [e.bone_index, e.animation_track] : [32767, -1] }
661
+
662
+ @entries.each { |e|
663
+ if e
664
+ reverse_table[e].offset = last_offset
665
+ last_offset += e.__size
666
+ else
667
+ reverse_table[e].offset = 0
668
+ end
669
+ }
670
+ @interpolations.each { |i|
671
+ if i
672
+ reverse_interpolation_table[i].offset_interpolation = last_offset
673
+ last_offset += i.size
674
+ end
675
+ }
676
+
677
+ @entries = @records.collect { |r| table[r] }
678
+ @interpolation = @records.collect { |r| interpolation_table[r] }
679
+ self
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 != "exp\0".b
687
+ u_a = f.read(4).unpack(int).first
688
+ offset_record = f.read(4).unpack(int).first
689
+ num_record = f.read(4).unpack(int).first
690
+
691
+ num_record >= 0 && offset_record > 0 && offset_record < f.size
692
+ }
693
+ big = block.call("l>")
694
+ f.rewind
695
+ small = block.call("l<")
696
+ f.rewind
697
+ raise "Invalid data!" unless big ^ small
698
+ return big
699
+ end
700
+
701
+ def self.is_bayo2?(f, big)
702
+ f.rewind
703
+ id = f.read(4)
704
+ uint = "L<"
705
+ uint = "L>" if big
706
+ version = f.read(4).unpack(uint).first
707
+ f.rewind
708
+ return version == 0x20110714
709
+ end
710
+
711
+ def self.convert(input_name, output_name, input_big = true, output_big = false)
712
+ input = File.open(input_name, "rb")
713
+ id = input.read(4).unpack("a4").first
714
+ raise "Invalid file type #{id}!" unless id == "exp\0".b
715
+ output = File.open(output_name, "wb")
716
+ output.write("\x00"*input.size)
717
+ input.seek(0);
718
+ output.seek(0);
719
+
720
+ if is_bayo2?(input, input_big)
721
+ exp = EXPFile2::new
722
+ else
723
+ exp = self::new
724
+ end
725
+ exp.__convert(input, output, input_big, output_big)
726
+
727
+ input.close
728
+ output.close
729
+ end
730
+
731
+ def self.load(input_name)
732
+ if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
733
+ input = input_name
734
+ else
735
+ input = File.open(input_name, "rb")
736
+ end
737
+ input_big = is_big?(input)
738
+
739
+ if is_bayo2?(input, input_big)
740
+ exp = EXPFile2::new
741
+ else
742
+ exp = self::new
743
+ end
744
+ exp.instance_variable_set(:@__was_big, input_big)
745
+ exp.__load(input, input_big)
746
+ input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
747
+
748
+ exp
749
+ end
750
+
751
+ def dump(output_name, output_big = false)
752
+ if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
753
+ output = output_name
754
+ else
755
+ output = File.open(output_name, "wb")
756
+ end
757
+ output.rewind
758
+
759
+ __set_dump_state(output, output_big, nil, nil)
760
+ __dump_fields
761
+ __unset_dump_state
762
+ output.close unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
763
+ self
764
+ end
765
+
766
+ end
767
+
768
+ end