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,472 @@
1
+ require 'optparse'
2
+ require 'set'
3
+ require_relative '../../bayonetta.rb'
4
+ require 'yaml'
5
+ require 'shellwords'
6
+ include Bayonetta
7
+
8
+ def get_bone_mapping(source, target)
9
+ mapping = source.each.collect { |p|
10
+ distance = [Float::INFINITY, Float::INFINITY]
11
+ min_index = nil
12
+ target.each { |q|
13
+ d = p.distance(q)
14
+ if ( d[0] <= distance[0] && d[1] < distance[1] ) || d[0] < distance[0]
15
+ distance = d
16
+ min_index = q.index
17
+ end
18
+ }
19
+ [p.index, min_index]
20
+ }.to_h
21
+ end
22
+
23
+ def apply_mapping(mapping, meshes)
24
+ meshes.each { |m|
25
+ m.batches.each { |b|
26
+ b.bone_refs.collect! { |i|
27
+ mapping[i]
28
+ }
29
+ }
30
+ }
31
+ end
32
+
33
+ def get_bone_indexes(vertexes)
34
+ s = Set::new
35
+ vertexes.each { |v|
36
+ bi = v.bone_index
37
+ nbi = 0x0
38
+ ia = 4.times.collect { |i|
39
+ ni = bi & 0xff
40
+ bi >>= 8
41
+ s.add(ni)
42
+ }
43
+ }
44
+ s
45
+ end
46
+
47
+ def merge_bones(wmb1, wmb2)
48
+
49
+ tt1 = wmb1.bone_index_translate_table.table
50
+ tt2_orig = wmb2.bone_index_translate_table.table
51
+ tt2 = tt2_orig.invert
52
+
53
+ bones1 = wmb1.get_bone_structure
54
+ bones2 = wmb2.get_bone_structure
55
+
56
+ #works but for the arms
57
+ #F..ing subtree isomorphism problem
58
+ #mapping = get_bone_mapping(bones2, bones1)
59
+
60
+ if $options[:bone_map]
61
+ if $options[:bone_map] == "same"
62
+ common_mapping = tt2_orig.keys.collect { |k| [k,k] }.to_h
63
+ else
64
+ common_mapping = YAML::load_file( $options[:bone_map] )
65
+ end
66
+ else
67
+ common_mapping = {}
68
+ end
69
+ #common_bones = YAML::load_file("Bayonetta2_common_bones.yaml")
70
+ #mapping = YAML::load_file("Bayo2_pl0010_Bayo_pl0010_bone_mapping.yaml")
71
+
72
+ #mapping in local indexes
73
+ mapping = {}
74
+
75
+ tt2.each { |key, val|
76
+ mapping[key] = tt1[common_mapping[val]]
77
+ }
78
+ mapping = mapping.to_a.sort { |e1, e2| e1.first <=> e2.first }.to_h
79
+
80
+ #update bone positions to meet imported model's ones.
81
+ if $options[:update_bones]
82
+ mapping.select { |k,v| v }.each { |k,v|
83
+ bones1[v].position = bones2[k].position
84
+ }
85
+ end
86
+ #missing_bones = mapping.select { |k,v| v.nil? }.collect { |k,v| bones2[k] }
87
+ #missing_mapping = get_bone_mapping(missing_bones, bones1)
88
+ #p missing_mapping
89
+ #mapping.update(missing_mapping)
90
+ #p mapping
91
+
92
+ mapping[-1] = -1
93
+ missing_bones = mapping.select { |k,v| v.nil? }.collect { |k,v| k }
94
+ new_bone_index = bones1.size
95
+ new_bone_indexes = []
96
+ missing_bones.each { |bi|
97
+ mapping[bi] = new_bone_index
98
+ new_bone_indexes.push(new_bone_index)
99
+
100
+ b = bones2[bi].dup
101
+ b.index = new_bone_index
102
+ b.parent = bones1[mapping[b.parent.index]] if b.parent
103
+ b.symmetric = b.symmetric ? b.symmetric : -1
104
+ b.flag = b.flag ? b.flag : 5
105
+
106
+ bones1.push b
107
+ new_bone_index += 1
108
+ }
109
+ wmb1.set_bone_structure(bones1)
110
+
111
+ missing_bones_count = missing_bones.length
112
+
113
+ raise "Too many bones to add!" if missing_bones_count > 0x100
114
+
115
+ #missing_bones_slots = align(missing_bones_count, 0x10)/0x10
116
+ (align(missing_bones_count, 0x10) - missing_bones_count).times {
117
+ new_bone_indexes.push(0xfff)
118
+ }
119
+
120
+ used_indexes = tt1.keys
121
+ start_index = nil
122
+ #find a free range to add new bone data
123
+ (0x250..(0x1000-new_bone_indexes.size)).step(0x10) { |s_index|
124
+ if (used_indexes & (s_index..(s_index+new_bone_indexes.size)).to_a) == []
125
+ start_index = s_index
126
+ break
127
+ end
128
+ }
129
+ raise "No room available in translate table!" unless start_index
130
+ new_tt = wmb1.bone_index_translate_table.table.dup
131
+ new_bone_indexes.each_with_index { |ind, i|
132
+ new_tt[i+start_index] = ind
133
+ common_mapping[tt2[missing_bones[i]]] = i + start_index if i < missing_bones.length && missing_bones[i]
134
+ }
135
+ wmb1.bone_index_translate_table.table = new_tt
136
+
137
+ #update bone symmetries
138
+ if wmb1.bone_symmetries
139
+ (-missing_bones_count..-1).each { |i|
140
+ symmetric = common_mapping[wmb1.bone_symmetries[i]]
141
+ symmetric = -1 unless symmetric
142
+ wmb1.bone_symmetries[i] = symmetric
143
+ }
144
+ end
145
+ #mapping.each_with_index { |i, j|
146
+ # p = bones2[j]
147
+ # q = bones1[i]
148
+ # puts "#{j} -> #{i} : #{p.distance(q)}"
149
+ #}
150
+
151
+ apply_mapping(mapping, wmb2.meshes)
152
+
153
+ common_mapping
154
+ end
155
+
156
+ def merge_vertexes(wmb1, wmb2)
157
+ num_vertex1 = wmb1.header.num_vertexes
158
+ num_vertex2 = wmb2.header.num_vertexes
159
+
160
+ vertex_types = wmb1.get_vertex_types
161
+
162
+ wmb1.vertexes += num_vertex2.times.collect {
163
+ vertex_types[0]::new
164
+ }
165
+
166
+ if wmb1.vertexes_ex_data
167
+ wmb1.vertexes_ex_data += num_vertex2.times.collect {
168
+ vertex_types[1]::new
169
+ }
170
+ end
171
+
172
+ wmb1.header.num_vertexes += num_vertex2
173
+
174
+ wmb1.get_vertex_fields.each { |field|
175
+ unless wmb2.get_vertex_field(field, 0)
176
+ warn "Couldn't find vertex field #{field} in model 2"
177
+ if field == :color
178
+ warn "Using default value 0xc0 0xc0 0xc0 0xff"
179
+ c = Color::new
180
+ c.r = 0xc0
181
+ c.g = 0xc0
182
+ c.b = 0xc0
183
+ c.a = 0xff
184
+ num_vertex2.times { |i|
185
+ wmb1.set_vertex_field(field, num_vertex1 + i, c)
186
+ }
187
+ elsif field == :mapping2
188
+ warn "Using mapping as default"
189
+ num_vertex2.times { |i|
190
+ wmb1.set_vertex_field(field, num_vertex1 + i, wmb2.get_vertex_field(:mapping, i))
191
+ }
192
+ else
193
+ warn "No suitable default found..."
194
+ end
195
+ else
196
+ num_vertex2.times { |i|
197
+ wmb1.set_vertex_field(field, num_vertex1 + i, wmb2.get_vertex_field(field, i))
198
+ }
199
+ end
200
+ }
201
+ return num_vertex1
202
+ end
203
+
204
+ def merge_meshes(wmb1, wmb2)
205
+ new_vertex_offset = wmb1.header.num_vertexes - wmb2.header.num_vertexes
206
+ mesh_offset = align(wmb1.meshes_offsets.last + wmb1.meshes.last.__size, 0x20)
207
+ new_meshes_offset = wmb2.meshes_offsets.collect { |e|
208
+ e + mesh_offset
209
+ }
210
+ wmb2.meshes.each_with_index { |m, i|
211
+ m.header.id = i + wmb1.header.num_meshes
212
+ m.batches.each { |b|
213
+ b.header.mesh_id = m.header.id
214
+ if !wmb1.is_bayo2? && wmb2.is_bayo2?
215
+ b.header.batch_id = 0x0
216
+ b.header.flags = 0x8001
217
+ if b.header.u_e1 == 0x10
218
+ b.header.u_e1 = 0x0
219
+ elsif b.header.u_e1 == 0x30
220
+ b.header.u_e1 = 0x20
221
+ b.header.u_e2 = 0x0f
222
+ end
223
+ end
224
+ b.header.vertex_start += new_vertex_offset
225
+ b.header.vertex_end += new_vertex_offset
226
+ b.header.vertex_offset += new_vertex_offset
227
+ }
228
+ }
229
+
230
+ wmb1.header.num_meshes += wmb2.header.num_meshes
231
+ wmb1.meshes += wmb2.meshes
232
+ wmb1.meshes_offsets += new_meshes_offset
233
+ end
234
+
235
+ def merge_materials(wmb1, wmb2, tex_map)
236
+ new_mat_offset = wmb1.header.num_materials
237
+ mat_offset = wmb1.materials_offsets.last + wmb1.materials.last.__size
238
+ new_materials_offsets = []
239
+ new_materials = []
240
+ if wmb2.tex_infos then #Bayo 2
241
+ wmb2.materials.each_with_index { |e, i|
242
+ #biggest known material( in fact biggset is 0x174)
243
+ new_materials_offsets.push(mat_offset + i*0x124)
244
+ m = WMBFile::Material::new
245
+ m.type = 0x0
246
+ m.flag = 0x0
247
+ m.material_data = [0x0]*(0x120/4)
248
+ m.material_data[0] = (tex_map[e.material_data[0]] ? tex_map[e.material_data[0]] : 0x80000000)
249
+ m.material_data[1] = (tex_map[e.material_data[3]] ? tex_map[e.material_data[3]] : 0x80000000)
250
+ new_materials.push(m)
251
+ }
252
+ wmb2.meshes.each { |m|
253
+ m.batches.each { |b|
254
+ b.header.material_id = b.header.ex_mat_id + new_mat_offset
255
+ b.header.ex_mat_id = 0x0
256
+ }
257
+ }
258
+ else #Bayo 1
259
+ wmb2.materials.each_with_index { |e, i|
260
+ new_materials_offsets.push(mat_offset)
261
+ mat_offset += e.__size
262
+ m = WMBFile::Material::new
263
+ m.type = e.type
264
+ m.flag = e.flag
265
+ m.material_data = e.material_data.dup
266
+ if bayo_mat_properties[m.type]
267
+ bayomat = bayo_mat_properties[m.type]
268
+ bayomat.tex_num.times { |j|
269
+ m.material_data[j] = ( tex_map[e.material_data[j]] ? tex_map[e.material_data[j]] : e.material_data[j] )
270
+ }
271
+ else
272
+ warn "Unknow material type 0x#{m.type.to_s(16)}!"
273
+ 5.times { |j|
274
+ m.material_data[j] = ( tex_map[e.material_data[j]] ? tex_map[e.material_data[j]] : e.material_data[j] )
275
+ }
276
+ end
277
+ new_materials.push(m)
278
+ }
279
+ wmb2.meshes.each { |m|
280
+ m.batches.each { |b|
281
+ b.header.material_id = b.header.material_id + new_mat_offset
282
+ }
283
+ }
284
+ end
285
+
286
+
287
+ wmb1.header.num_materials += wmb2.header.num_materials
288
+ wmb1.materials += new_materials
289
+ wmb1.materials_offsets += new_materials_offsets
290
+ end
291
+
292
+ def get_texture_map(tex1, tex2)
293
+ offset = tex1.each.count
294
+ tex_map = {}
295
+ tex2.each.each_with_index { |t,i|
296
+ info, _ = t
297
+ _, _, idx = info
298
+ idx = i unless idx
299
+ tex_map[idx] = i+offset
300
+ }
301
+ tex_map
302
+ end
303
+
304
+ class BayoMat
305
+ attr_reader :code
306
+ attr_reader :size
307
+ attr_reader :tex_num
308
+ attr_reader :lightmap_index
309
+ attr_reader :normalmap_index
310
+ attr_reader :second_diffuse_index
311
+ attr_reader :reflection_index
312
+ def initialize(code, size, tex_num, lightmap_index, normalmap_index, second_diffuse_index, reflection_index)
313
+ @code = code
314
+ @size = size
315
+ @tex_num = tex_num
316
+ @lightmap_index = lightmap_index
317
+ @normalmap_index = normalmap_index
318
+ @second_diffuse_index = second_diffuse_index
319
+ @reflexion_index = reflection_index
320
+ end
321
+ end
322
+
323
+ @material_database = YAML::load_file(File.join(__dir__,"..", "material_database.yaml"))
324
+ @mat_properties = @material_database.select { |k, h|
325
+ h[:layout]
326
+ }.collect { |k, h|
327
+ tex_num = h[:layout].count { |k, v| v.match("sampler") }
328
+ lightmap_index = h[:layout].find_index { |k, v| k == "lightmap" && v.match("sampler") }
329
+ lightmap_index = -1 unless lightmap_index
330
+ normalmap_index = h[:layout].find_index { |k, v| k == "reliefmap" && v.match("sampler") }
331
+ normalmap_index = -1 unless normalmap_index
332
+ second_diffuse_index = h[:layout].find_index { |k, v| k == "Color_2" && v.match("sampler") }
333
+ second_diffuse_index = -1 unless second_diffuse_index
334
+ reflection_index = h[:layout].find_index { |k, v| k == "envmap" && v.match("sampler") }
335
+ reflection_index = -1 unless reflection_index
336
+ mat_info = BayoMat.new(k, h[:size], tex_num, lightmap_index, normalmap_index, second_diffuse_index, reflection_index)
337
+ [k, mat_info]
338
+ }.to_h
339
+
340
+ def bayo_mat_properties
341
+ return @mat_properties
342
+ {
343
+ 0x31 => BayoMat::new(0x31, 0xC0, 3, 1, -1, -1, -1),
344
+ 0x32 => BayoMat::new(0x32, 0xE4, 4, 1, -1, -1, 3),
345
+ 0x33 => BayoMat::new(0x33, 0xD4, 4, 2, -1, 1, -1),
346
+ 0x34 => BayoMat::new(0x34, 0xF8, 5, 2, -1, 1, 4),
347
+ 0x38 => BayoMat::new(0x38, 0xD4, 4, -1, 2, -1, -1),
348
+ 0x3A => BayoMat::new(0x3A, 0xD4, 4, 1, 2, -1, -1),
349
+ 0x3C => BayoMat::new(0x3C, 0xD4, 4, -1, -1, -1, -1),
350
+ 0x40 => BayoMat::new(0x40, 0xC4, 4, -1, -1, -1, -1),
351
+ 0x42 => BayoMat::new(0x42, 0xAC, 2, -1, -1, -1, -1),
352
+ 0x44 => BayoMat::new(0x44, 0xE4, 4, 1, -1, -1, -1),
353
+ 0x47 => BayoMat::new(0x47, 0x68, 1, -1, -1, -1, -1),
354
+ 0x48 => BayoMat::new(0x48, 0xC0, 3, 1, -1, 2, -1),
355
+ 0x4A => BayoMat::new(0x4A, 0xD4, 4, 2, -1, 1, -1),
356
+ 0x4B => BayoMat::new(0x4B, 0xD4, 4, -1, 2, -1, -1),
357
+ 0x4C => BayoMat::new(0x4C, 0xAC, 2, -1, -1, -1, -1),
358
+ 0x53 => BayoMat::new(0x53, 0x68, 1, -1, -1, -1, -1),
359
+ 0x54 => BayoMat::new(0x54, 0xD4, 4, 1, -1, -1, -1),
360
+ 0x59 => BayoMat::new(0x59, 0xD4, 4, 1, -1, -1, -1),
361
+ 0x60 => BayoMat::new(0x60, 0x68, 1, -1, -1, -1, -1),
362
+ 0x68 => BayoMat::new(0x68, 0xAC, 2, -1, -1, -1, -1),
363
+ 0x6B => BayoMat::new(0x6B, 0xD0, 3, -1, 1, -1, -1),
364
+ 0x6D => BayoMat::new(0x6D, 0xD0, 3, -1, 1, -1, -1),
365
+ 0x6E => BayoMat::new(0x6E, 0xD4, 4, -1, 1, -1, -1),
366
+ 0x71 => BayoMat::new(0x71, 0xE4, 4, 1, -1, -1, -1),
367
+ 0x72 => BayoMat::new(0x72, 0xD4, 4, -1, 1, -1, -1),
368
+ 0x75 => BayoMat::new(0x75, 0xAC, 2, -1, -1, -1, -1),
369
+ 0x7C => BayoMat::new(0x7C, 0xEA, 4, 1, -1, -1, 3),
370
+ 0x7F => BayoMat::new(0x7F, 0x124,4, -1, 1, -1, -1),
371
+ 0x81 => BayoMat::new(0x81, 0x120,3, -1, -1, -1, -1),
372
+ 0x83 => BayoMat::new(0x83, 0xAC, 2, -1, -1, -1, -1),
373
+ 0x87 => BayoMat::new(0x87, 0xD4, 4, -1, 1, -1, -1),
374
+ 0x89 => BayoMat::new(0x89, 0xC0, 3, 1, -1, -1, 2),
375
+ 0x8F => BayoMat::new(0x8F, 0xD4, 4, 1, -1, 2, 3),
376
+ 0x97 => BayoMat::new(0x97, 0x114,4, -1, -1, -1, -1),
377
+ 0xA1 => BayoMat::new(0xA1, 0xB0, 3, 1, -1, -1, -1),
378
+ 0xA3 => BayoMat::new(0xA3, 0xE4, 4, -1, 1, -1, -1),
379
+ 0xB2 => BayoMat::new(0xB2, 0xD4, 4, -1, 1, -1, -1),
380
+ 0xB3 => BayoMat::new(0xB3, 0x124,4, -1, 1, -1, -1)
381
+ }
382
+ end
383
+
384
+ def get_shader_map
385
+ {
386
+ "ois00_xbceX" => 0xB3,
387
+ "ois01_xbweX" => 0x7f,
388
+ "ois20_xbceX" => 0xB2,
389
+ "skn03_xbXXX" => 0x87,
390
+ "alp03_sbXXX" => 0x42,
391
+ "har01_sbXtX" => 0x84
392
+ }
393
+ end
394
+
395
+ $options = {}
396
+
397
+ OptionParser.new do |opts|
398
+ opts.banner = "Usage: wmb_import_geometry_wiiu_pc.rb target_file source_file [options]"
399
+
400
+ opts.on("-bFILE", "--bone-map=FILE", "Bone map") do |bone_map|
401
+ $options[:bone_map] = bone_map
402
+ end
403
+
404
+ opts.on("-u", "--update-bones", "Update recognized bone positions") do |update_bones|
405
+ $options[:update_bones] = update_bones
406
+ end
407
+
408
+ opts.on("-t", "--[no-]import-textures", "Import textures also") do |import_textures|
409
+ $options[:import_textures] = import_textures
410
+ end
411
+
412
+ opts.on("-o", "--[no-]overwrite", "Overwrite destination files") do |overwrite|
413
+ $options[:overwrite] = overwrite
414
+ end
415
+
416
+ opts.on("-h", "--help", "Prints this help") do
417
+ puts opts
418
+ exit
419
+ end
420
+
421
+ end.parse!
422
+
423
+ input_file1 = ARGV[0]
424
+ input_file2 = ARGV[1]
425
+
426
+ raise "Invalid file #{input_file1}" unless File::file?(input_file1)
427
+ raise "Invalid file #{input_file2}" unless File::file?(input_file2)
428
+
429
+ Dir.mkdir("wmb_output") unless Dir.exist?("wmb_output")
430
+
431
+ wmb1 = WMBFile::load(input_file1)
432
+ wmb2 = WMBFile::load(input_file2)
433
+
434
+ if $options[:import_textures]
435
+ tex1_file_name = input_file1.gsub(/wmb\z/,"wtb")
436
+ tex1 = WTBFile::new(File::new(tex1_file_name, "rb"))
437
+ begin
438
+ tex2_file_name = input_file2.gsub(/wmb\z/,"wta")
439
+ tex2 = WTBFile::new(File::new(tex2_file_name, "rb"), true, File::new(input_file2.gsub(/wmb\z/,"wtp"), "rb"))
440
+ rescue
441
+ tex2_file_name = input_file2.gsub(/wmb\z/,"wtb")
442
+ tex2 = WTBFile::new(File::new(tex2_file_name, "rb"))
443
+ end
444
+ end
445
+
446
+ tex_map = get_texture_map(tex1, tex2)
447
+
448
+ merge_vertexes(wmb1, wmb2)
449
+
450
+ common_mapping = merge_bones(wmb1, wmb2)
451
+
452
+ merge_materials(wmb1, wmb2, tex_map)
453
+
454
+ merge_meshes(wmb1, wmb2)
455
+
456
+ wmb1.recompute_relative_positions if $options[:update_bones]
457
+
458
+ wmb1.recompute_layout
459
+
460
+ File::open(File.join("wmb_output","#{File::basename(input_file2,".wmb")}_#{File::basename(input_file1,".wmb")}_bone_map.yaml"), "w") { |f|
461
+ f.write YAML::dump(common_mapping)
462
+ }
463
+
464
+ if $options[:overwrite]
465
+ wmb1.dump(input_file1)
466
+ else
467
+ wmb1.dump(File.join("wmb_output",File.basename(input_file1)))
468
+ end
469
+
470
+ if $options[:import_textures]
471
+ `ruby #{Shellwords.escape File.join(__dir__,"wtb_import_textures.rb")} #{Shellwords.escape tex1_file_name} #{Shellwords.escape tex2_file_name}#{$options[:overwrite] ? " --overwrite" : ""}`
472
+ end