pgtools 1.0.0 → 1.0.2

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 +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 +474 -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
@@ -1,472 +1,474 @@
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
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
+ tex_map = {}
435
+
436
+ if $options[:import_textures]
437
+ tex1_file_name = input_file1.gsub(/wmb\z/,"wtb")
438
+ tex1 = WTBFile::new(File::new(tex1_file_name, "rb"))
439
+ begin
440
+ tex2_file_name = input_file2.gsub(/wmb\z/,"wta")
441
+ tex2 = WTBFile::new(File::new(tex2_file_name, "rb"), true, File::new(input_file2.gsub(/wmb\z/,"wtp"), "rb"))
442
+ rescue
443
+ tex2_file_name = input_file2.gsub(/wmb\z/,"wtb")
444
+ tex2 = WTBFile::new(File::new(tex2_file_name, "rb"))
445
+ end
446
+
447
+ tex_map = get_texture_map(tex1, tex2)
448
+ end
449
+
450
+ merge_vertexes(wmb1, wmb2)
451
+
452
+ common_mapping = merge_bones(wmb1, wmb2)
453
+
454
+ merge_materials(wmb1, wmb2, tex_map)
455
+
456
+ merge_meshes(wmb1, wmb2)
457
+
458
+ wmb1.recompute_relative_positions if $options[:update_bones]
459
+
460
+ wmb1.recompute_layout
461
+
462
+ File::open(File.join("wmb_output","#{File::basename(input_file2,".wmb")}_#{File::basename(input_file1,".wmb")}_bone_map.yaml"), "w") { |f|
463
+ f.write YAML::dump(common_mapping)
464
+ }
465
+
466
+ if $options[:overwrite]
467
+ wmb1.dump(input_file1)
468
+ else
469
+ wmb1.dump(File.join("wmb_output",File.basename(input_file1)))
470
+ end
471
+
472
+ if $options[:import_textures]
473
+ `ruby #{Shellwords.escape File.join(__dir__,"wtb_import_textures.rb")} #{Shellwords.escape tex1_file_name} #{Shellwords.escape tex2_file_name}#{$options[:overwrite] ? " --overwrite" : ""}`
474
+ end