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