pgtools 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +25 -0
  3. data/bin/bxm_decoder +2 -0
  4. data/bin/bxm_encoder +2 -0
  5. data/bin/clh_convert +2 -0
  6. data/bin/clp_convert +2 -0
  7. data/bin/clw_convert +2 -0
  8. data/bin/dat_creator +2 -0
  9. data/bin/dat_extractor +2 -0
  10. data/bin/dat_ls +2 -0
  11. data/bin/eff_idd_creator +2 -0
  12. data/bin/eff_idd_extractor +2 -0
  13. data/bin/exp_convert_wiiu_pc +2 -0
  14. data/bin/exp_tool +2 -0
  15. data/bin/mot_convert_wiiu_pc +2 -0
  16. data/bin/mot_tool +2 -0
  17. data/bin/pkz_extractor +2 -0
  18. data/bin/scr_creator +2 -0
  19. data/bin/scr_extractor +2 -0
  20. data/bin/wmb_cleanup +2 -0
  21. data/bin/wmb_common_bones +2 -0
  22. data/bin/wmb_convert_pc_switch +2 -0
  23. data/bin/wmb_convert_wiiu_pc +2 -0
  24. data/bin/wmb_export_assimp +2 -0
  25. data/bin/wmb_get_bone_map +2 -0
  26. data/bin/wmb_import_assimp +2 -0
  27. data/bin/wmb_import_nier +2 -0
  28. data/bin/wmb_import_wiiu +2 -0
  29. data/bin/wtb_convert_wiiu_pc +2 -0
  30. data/bin/wtx_creator +2 -0
  31. data/bin/wtx_extractor +2 -0
  32. data/lib/bayonetta/alignment.rb +14 -0
  33. data/lib/bayonetta/bone.rb +55 -0
  34. data/lib/bayonetta/bxm.rb +180 -0
  35. data/lib/bayonetta/clh.rb +159 -0
  36. data/lib/bayonetta/clp.rb +212 -0
  37. data/lib/bayonetta/clw.rb +166 -0
  38. data/lib/bayonetta/dat.rb +261 -0
  39. data/lib/bayonetta/eff.rb +314 -0
  40. data/lib/bayonetta/endianness.rb +53 -0
  41. data/lib/bayonetta/exp.rb +768 -0
  42. data/lib/bayonetta/linalg.rb +416 -0
  43. data/lib/bayonetta/material_database.yaml +2581 -0
  44. data/lib/bayonetta/mot.rb +763 -0
  45. data/lib/bayonetta/pkz.rb +63 -0
  46. data/lib/bayonetta/scr.rb +393 -0
  47. data/lib/bayonetta/tools/bxm_decoder.rb +23 -0
  48. data/lib/bayonetta/tools/bxm_encoder.rb +37 -0
  49. data/lib/bayonetta/tools/clh_convert.rb +60 -0
  50. data/lib/bayonetta/tools/clp_convert.rb +70 -0
  51. data/lib/bayonetta/tools/clw_convert.rb +60 -0
  52. data/lib/bayonetta/tools/dat_creator.rb +57 -0
  53. data/lib/bayonetta/tools/dat_extractor.rb +94 -0
  54. data/lib/bayonetta/tools/dat_ls.rb +106 -0
  55. data/lib/bayonetta/tools/eff_idd_creator.rb +66 -0
  56. data/lib/bayonetta/tools/eff_idd_extractor.rb +73 -0
  57. data/lib/bayonetta/tools/exp_convert_wiiu_pc.rb +33 -0
  58. data/lib/bayonetta/tools/exp_tool.rb +48 -0
  59. data/lib/bayonetta/tools/mot_convert_wiiu_pc.rb +33 -0
  60. data/lib/bayonetta/tools/mot_tool.rb +60 -0
  61. data/lib/bayonetta/tools/pkz_extractor.rb +75 -0
  62. data/lib/bayonetta/tools/scr_creator.rb +63 -0
  63. data/lib/bayonetta/tools/scr_extractor.rb +78 -0
  64. data/lib/bayonetta/tools/wmb_cleanup.rb +250 -0
  65. data/lib/bayonetta/tools/wmb_common_bones.rb +45 -0
  66. data/lib/bayonetta/tools/wmb_convert_pc_switch.rb +35 -0
  67. data/lib/bayonetta/tools/wmb_convert_wiiu_pc.rb +33 -0
  68. data/lib/bayonetta/tools/wmb_export_assimp.rb +479 -0
  69. data/lib/bayonetta/tools/wmb_get_bone_map.rb +50 -0
  70. data/lib/bayonetta/tools/wmb_import_assimp.rb +735 -0
  71. data/lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb +472 -0
  72. data/lib/bayonetta/tools/wmb_import_nier.rb +309 -0
  73. data/lib/bayonetta/tools/wtb_convert_wiiu_pc.rb +95 -0
  74. data/lib/bayonetta/tools/wtb_import_textures.rb +103 -0
  75. data/lib/bayonetta/tools/wtx_creator.rb +69 -0
  76. data/lib/bayonetta/tools/wtx_extractor.rb +85 -0
  77. data/lib/bayonetta/vertex_types.yaml +213 -0
  78. data/lib/bayonetta/vertex_types2.yaml +164 -0
  79. data/lib/bayonetta/vertex_types_nier.yaml +145 -0
  80. data/lib/bayonetta/wmb.rb +2443 -0
  81. data/lib/bayonetta/wmb3.rb +759 -0
  82. data/lib/bayonetta/wtb.rb +481 -0
  83. data/lib/bayonetta.rb +60 -0
  84. metadata +254 -0
@@ -0,0 +1,309 @@
1
+ require 'optparse'
2
+ require 'set'
3
+ require_relative '../../bayonetta.rb'
4
+ require 'yaml'
5
+ require 'shellwords'
6
+ include Bayonetta
7
+
8
+ def merge_bones(wmb1, wmb2)
9
+
10
+ tt1 = wmb1.bone_index_translate_table.table
11
+ tt2_orig = wmb2.bone_index_translate_table.table
12
+ tt2 = tt2_orig.invert
13
+
14
+ bones1 = wmb1.get_bone_structure
15
+ if $options[:bone_map]
16
+ common_mapping = YAML::load_file( $options[:bone_map] )
17
+ else
18
+ common_mapping = {}
19
+ end
20
+
21
+ mapping = {}
22
+
23
+ tt2.each { |key, val|
24
+ mapping[key] = tt1[common_mapping[val]]
25
+ }
26
+ mapping = mapping.to_a.sort { |e1, e2| e1.first <=> e2.first }.to_h
27
+
28
+ if $options[:update_bones]
29
+ mapping.select { |k,v| v }.each { |k,v|
30
+ bones1[v].position = wmb2.bones[k].position
31
+ }
32
+ end
33
+
34
+ mapping[-1] = -1
35
+ missing_bones = mapping.select { |k,v| v.nil? }.collect { |k,v| k }
36
+ if $options[:filter_bones]
37
+ missing_bones -= $options[:filter_bones]
38
+ end
39
+ new_bone_index = bones1.size
40
+ new_bone_indexes = []
41
+ missing_bones.each { |bi|
42
+ mapping[bi] = new_bone_index
43
+ new_bone_indexes.push(new_bone_index)
44
+
45
+ b = Bone::new(wmb2.bones[bi].position)
46
+ b.index = new_bone_index
47
+ b.parent = bones1[mapping[wmb2.bones[bi].parent_index]] if wmb2.bones[bi].parent_index != -1
48
+ b.symmetric = -1
49
+ b.flag = 5
50
+
51
+ bones1.push b
52
+ new_bone_index += 1
53
+ }
54
+ wmb1.set_bone_structure(bones1)
55
+ missing_bones_count = missing_bones.length
56
+ raise "Too many bones to add!" if missing_bones_count > 0x100
57
+ (align(missing_bones_count, 0x10) - missing_bones_count).times {
58
+ new_bone_indexes.push(0xfff)
59
+ }
60
+
61
+ used_indexes = tt1.keys
62
+ start_index = nil
63
+
64
+ (0x250..(0x1000-new_bone_indexes.size)).step(0x10) { |s_index|
65
+ if (used_indexes & (s_index..(s_index+new_bone_indexes.size)).to_a) == []
66
+ start_index = s_index
67
+ break
68
+ end
69
+ }
70
+ raise "No room available in translate table!" unless start_index
71
+ new_tt = wmb1.bone_index_translate_table.table.dup
72
+ new_bone_indexes.each_with_index { |ind, i|
73
+ new_tt[i+start_index] = ind
74
+ common_mapping[tt2[missing_bones[i]]] = i + start_index if i < missing_bones.length && missing_bones[i]
75
+ }
76
+ wmb1.bone_index_translate_table.table = new_tt
77
+
78
+ if wmb1.bone_symmetries
79
+ (-missing_bones_count..-1).each { |i|
80
+ symmetric = common_mapping[wmb1.bone_symmetries[i]]
81
+ symmetric = -1 unless symmetric
82
+ wmb1.bone_symmetries[i] = symmetric
83
+ }
84
+ end
85
+
86
+ [common_mapping, mapping]
87
+ end
88
+
89
+ def get_texture_map(tex1, tex2)
90
+ offset = tex1.each.count
91
+ tex_map = {}
92
+ tex2.each.each_with_index { |t,i|
93
+ info, _ = t
94
+ _, _, idx = info
95
+ idx = i unless idx
96
+ tex_map[idx] = i+offset
97
+ }
98
+ tex_map
99
+ end
100
+
101
+ def merge_geometry(wmb1, wmb2, bone_mapping)
102
+ new_meshes = wmb2.header.info_meshes.number.times.collect { WMBFile::Mesh::new }
103
+ new_meshes.each_with_index { |m, i|
104
+ m.header.name = wmb2.meshes[i].name
105
+ m.header.id = i + wmb1.header.num_meshes
106
+ }
107
+
108
+ batch_infos_map = {}
109
+ wmb2.lods.each { |l|
110
+ l.batch_infos.each_with_index { |batch_info, i|
111
+ batch_infos_map[i+l.header.batch_start] = batch_info
112
+ }
113
+ }
114
+
115
+ vertex_types = wmb1.get_vertex_types
116
+
117
+ wmb2.batches.each_with_index { |n_b, batch_index|
118
+ v_g = wmb2.vertex_groups[n_b.vertex_group_index]
119
+ b_s = wmb2.bone_sets[n_b.bone_set_index]
120
+ b = WMBFile::Batch::new
121
+ first_vertex_index = wmb1.vertexes.length
122
+ indices = v_g.indices.slice(n_b.index_start, n_b.num_indices)
123
+ index_set = indices.uniq.sort
124
+ num_vertex = index_set.length
125
+ index_map = index_set.each_with_index.collect { |ind, i|
126
+ [ind, i+first_vertex_index]
127
+ }
128
+
129
+
130
+ wmb1.vertexes += num_vertex.times.collect {
131
+ vertex_types[0]::new
132
+ }
133
+ if wmb1.vertexes_ex_data
134
+ wmb1.vertexes_ex_data += num_vertex.times.collect {
135
+ vertex_types[1]::new
136
+ }
137
+ end
138
+ wmb1.header.num_vertexes += num_vertex
139
+
140
+ fields = wmb1.get_vertex_fields
141
+ fields.each { |field|
142
+ unless v_g.get_vertex_field(field, 0)
143
+ warn "Couldn't find vertex field #{field} in model 2"
144
+ if field == :color
145
+ warn "Using default value 0xc0 0xc0 0xc0 0xff"
146
+ c = Color::new
147
+ c.r = 0xc0
148
+ c.g = 0xc0
149
+ c.b = 0xc0
150
+ c.a = 0xff
151
+ index_map.each { |ind, i|
152
+ wmb1.set_vertex_field(field, i, c)
153
+ }
154
+ elsif field == :mapping2
155
+ warn "Using mapping as default"
156
+ index_map.each { |ind, i|
157
+ wmb1.set_vertex_field(field, i, v_g.get_vertex_field(:mapping, ind))
158
+ }
159
+ else
160
+ warn "No suitable default found"
161
+ end
162
+ else
163
+ if field == :normal
164
+ index_map.each { |ind, i|
165
+ n = Normal::new
166
+ n2 = v_g.get_vertex_field(:normal, ind)
167
+ n.x = n2.x
168
+ n.y = n2.y
169
+ n.z = n2.z
170
+ wmb1.set_vertex_field(field, i, n)
171
+ }
172
+ else
173
+ index_map.each { |ind, i|
174
+ wmb1.set_vertex_field(field, i, v_g.get_vertex_field(field, ind))
175
+ }
176
+ end
177
+ end
178
+ }
179
+
180
+ index_map = index_map.to_h
181
+
182
+ batch_info = batch_infos_map[batch_index]
183
+ mesh = new_meshes[batch_info.mesh_index]
184
+
185
+ b.header.material_id = batch_info.material_index + wmb1.header.num_materials
186
+ b.header.mesh_id = mesh.header.id
187
+ b.header.num_indices = indices.length
188
+ b.indices = indices.collect { |ind| index_map[ind] }
189
+ b.recompute_from_absolute_indices
190
+ b.bone_refs = b_s.bone_indices.collect { |bi| bone_mapping[wmb2.bone_map[bi]] }
191
+ b.num_bone_ref = b.bone_refs.length
192
+
193
+ mesh.batches.push b
194
+ mesh.header.num_batch += 1
195
+ }
196
+
197
+ wmb1.meshes += new_meshes
198
+ wmb1.header.num_meshes += new_meshes.length
199
+
200
+ end
201
+
202
+ def merge_materials(wmb1, wmb2, tex_map)
203
+ new_mat_offset = wmb1.header.num_materials
204
+ mat_offset = wmb1.materials_offsets.last + wmb1.materials.last.__size
205
+ new_materials_offsets = []
206
+ new_materials = []
207
+
208
+ wmb2.materials.each_with_index { |e, i|
209
+ #biggest known material( in fact biggset is 0x174)
210
+ new_materials_offsets.push(mat_offset + i*0x124)
211
+ m = WMBFile::Material::new
212
+ m.type = 0x0
213
+ m.flag = 0x0
214
+ m.material_data = [0x0]*(0x120/4)
215
+ albedo = e.textures.find { |t| t.name.match("g_AlbedoMap") }
216
+ normal = e.textures.find { |t| t.name.match("g_NormalMap") }
217
+ m.material_data[0] = (albedo ? tex_map[albedo.texture_id] : 0x80000000)
218
+ m.material_data[1] = (normal ? tex_map[normal.texture_id] : 0x80000000)
219
+ m.material_data[0] = (m.material_data[0] ? m.material_data[0] : 0x80000000)
220
+ m.material_data[1] = (m.material_data[1] ? m.material_data[1] : 0x80000000)
221
+ new_materials.push(m)
222
+ }
223
+
224
+ wmb1.header.num_materials += wmb2.header.info_materials.number
225
+ wmb1.materials += new_materials
226
+ wmb1.materials_offsets += new_materials_offsets
227
+ end
228
+
229
+ $options = {}
230
+
231
+ OptionParser.new do |opts|
232
+ opts.banner = "Usage: wmb_import_geometry_wiiu_pc.rb target_file source_file [options]"
233
+
234
+ opts.on("-bFILE", "--bone-map=FILE", "Bone map") do |bone_map|
235
+ $options[:bone_map] = bone_map
236
+ end
237
+
238
+ opts.on("-u", "--update-bones", "Update recognized bone positions") do |update_bones|
239
+ $options[:update_bones] = update_bones
240
+ end
241
+
242
+ opts.on("-t", "--[no-]import-textures", "Import textures also") do |import_textures|
243
+ $options[:import_textures] = import_textures
244
+ end
245
+
246
+ opts.on("-o", "--[no-]overwrite", "Overwrite destination files") do |overwrite|
247
+ $options[:overwrite] = overwrite
248
+ end
249
+
250
+ opts.on("-f", "--filter-bones=REJECT_LIST", "Don't import all bones") do |filter_bones|
251
+ $options[:filter_bones] = eval(filter_bones)
252
+ end
253
+
254
+ opts.on("-h", "--help", "Prints this help") do
255
+ puts opts
256
+ exit
257
+ end
258
+
259
+ end.parse!
260
+
261
+ input_file1 = ARGV[0]
262
+ input_file2 = ARGV[1]
263
+
264
+ raise "Invalid file #{input_file1}" unless File::file?(input_file1)
265
+ raise "Invalid file #{input_file2}" unless File::file?(input_file2)
266
+
267
+ Dir.mkdir("wmb_output") unless Dir.exist?("wmb_output")
268
+
269
+ wmb1 = WMBFile::load(input_file1)
270
+ wmb2 = WMBFile::load(input_file2)
271
+
272
+ tex_map = {}
273
+
274
+ if $options[:import_textures]
275
+ tex1_file_name = input_file1.gsub(/wmb\z/,"wtb")
276
+ tex1 = WTBFile::new(File::new(tex1_file_name, "rb"))
277
+ begin
278
+ tex2_file_name = input_file2.gsub(/wmb\z/,"wta")
279
+ tex2 = WTBFile::new(File::new(tex2_file_name, "rb"), true, File::new(input_file2.gsub(/wmb\z/,"wtp"), "rb"))
280
+ rescue
281
+ tex2_file_name = input_file2.gsub(/wmb\z/,"wtb")
282
+ tex2 = WTBFile::new(File::new(tex2_file_name, "rb"))
283
+ end
284
+
285
+ tex_map = get_texture_map(tex1, tex2)
286
+ end
287
+
288
+ common_mapping, bone_mapping = merge_bones(wmb1, wmb2)
289
+
290
+ merge_geometry(wmb1, wmb2, bone_mapping)
291
+
292
+ merge_materials(wmb1, wmb2, tex_map)
293
+
294
+ wmb1.recompute_relative_positions
295
+ wmb1.recompute_layout
296
+
297
+ File::open(File.join("wmb_output", "#{File::basename(input_file2,".wmb")}_#{File::basename(input_file1,".wmb")}_bone_map.yaml"), "w") { |f|
298
+ f.write YAML::dump(common_mapping)
299
+ }
300
+
301
+ if $options[:overwrite]
302
+ wmb1.dump(input_file1)
303
+ else
304
+ wmb1.dump(File.join("wmb_output", File.basename(input_file1)))
305
+ end
306
+
307
+ if $options[:import_textures]
308
+ `ruby #{Shellwords.escape File.join(__dir__,"wtb_import_textures.rb")} #{Shellwords.escape tex1_file_name} #{Shellwords.escape tex2_file_name}#{$options[:overwrite] ? " --overwrite" : ""}`
309
+ end
@@ -0,0 +1,95 @@
1
+ require 'optparse'
2
+ require_relative '../../bayonetta'
3
+ require 'shellwords'
4
+ include Bayonetta
5
+
6
+ # https://stackoverflow.com/a/5471032
7
+ def which(cmd)
8
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
9
+ exe = File.join(path, cmd)
10
+ return exe if File.executable?(exe) && !File.directory?(exe)
11
+ end
12
+ nil
13
+ end
14
+
15
+ $options = {
16
+ output: nil
17
+ }
18
+
19
+ OptionParser.new do |opts|
20
+ opts.banner = <<EOF
21
+ Usage: wtb_convert_wiiu_pc target_file
22
+ EOF
23
+ opts.on("-h", "--help", "Prints this help") do
24
+ puts opts
25
+ exit
26
+ end
27
+
28
+ opts.on("-o", "--output=filename", "file to output result") do |name|
29
+ $options[:output] = name
30
+ end
31
+
32
+ end.parse!
33
+
34
+ input_file = ARGV[0]
35
+
36
+ raise "Invalid file #{input_file}" unless input_file && File::file?(input_file)
37
+
38
+ if File.extname(input_file) == ".wta"
39
+ fl = WTBFile::new(File::new(input_file, "rb"), true, File::new(input_file.gsub(/wta\z/,"wtp"), "rb"))
40
+ else
41
+ fl = WTBFile::new(File::new(input_file, "rb"))
42
+ end
43
+ Dir.mkdir("tex_output") unless Dir.exist?("tex_output")
44
+ prefix = File.join("tex_output", File.basename(input_file, ".wtb"))
45
+ texs = fl.each.each_with_index.collect { |info_f, i|
46
+ info, f = info_f
47
+ ext, flags, idx = info
48
+ tex_name = "#{prefix}_#{"%03d"%i}#{ext}"
49
+ File::open(tex_name, "wb") { |f2|
50
+ f.rewind
51
+ f2.write(f.read)
52
+ }
53
+ [tex_name, [flags, idx]]
54
+ }
55
+
56
+ tex_conv_path = which("TexConv2.exe")
57
+ if !tex_conv_path
58
+ tex_conv_path = File.join(".", "TexConv2.exe")
59
+ if (!File.exist?(tex_conv_path))
60
+ tex_conv_path = File.join(File.expand_path(File.join(File.dirname(__FILE__), *[".."]*3)), "TexConv2.exe")
61
+ if (!File.exist?(tex_conv_path))
62
+ tex_conv_path = nil
63
+ end
64
+ end
65
+ end
66
+
67
+ fl2 = WTBFile::new
68
+ fl2.unknown = fl.unknown
69
+
70
+ texs.each { |name, info|
71
+ flags, idx = info
72
+ if File.extname(input_file) == ".wta"
73
+ flags &= 0xffffffdf #remove 0x20 flag
74
+ if flags == 0x70000000
75
+ flags = 0x10000000
76
+ else
77
+ flags = 0x20000000
78
+ end
79
+ else
80
+ flags &= 0xfffffffd #remove 0x2 flag
81
+ end
82
+ new_name = name.gsub("gtx","dds")
83
+ raise "could not locate TexConv2.exe, put it in your PATH" unless tex_conv_path
84
+ res = `#{Shellwords.escape tex_conv_path} -i #{Shellwords.escape name} -o #{Shellwords.escape new_name}`
85
+ raise "could not execute TexConv2.exe:\n#{res}" if !$?.success?
86
+ fl2.push( File::new(new_name, "rb"), flags, idx )
87
+ }
88
+
89
+ output_file = $options[:output]
90
+ if !output_file
91
+ Dir.mkdir("wtb_output") unless Dir.exist?("wtb_output")
92
+ output_file = File.join("wtb_output", "#{File.basename(input_file.gsub(/wta\z/,"wtb"))}")
93
+ end
94
+ fl2.dump(output_file)
95
+
@@ -0,0 +1,103 @@
1
+ require 'optparse'
2
+ require_relative '../../bayonetta.rb'
3
+ require 'shellwords'
4
+ include Bayonetta
5
+
6
+ # https://stackoverflow.com/a/5471032
7
+ def which(cmd)
8
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
9
+ exe = File.join(path, cmd)
10
+ return exe if File.executable?(exe) && !File.directory?(exe)
11
+ end
12
+ nil
13
+ end
14
+
15
+ $options = {}
16
+
17
+ OptionParser.new do |opts|
18
+ opts.banner = "Usage: wtb_import_textures.rb target_file source_file [options]"
19
+
20
+ opts.on("-o", "--[no-]overwrite", "Overwrite destination file") do |overwrite|
21
+ $options[:overwrite] = overwrite
22
+ end
23
+
24
+ opts.on("-h", "--help", "Prints this help") do
25
+ puts opts
26
+ exit
27
+ end
28
+
29
+ end.parse!
30
+
31
+ input_file1 = ARGV[0]
32
+ input_file2 = ARGV[1]
33
+ raise "Invalid file #{input_file1}" unless File::file?(input_file1)
34
+ fl0 = WTBFile::new(File::new(input_file1, "rb"))
35
+
36
+
37
+ raise "Invalid file #{input_file2}" unless File::file?(input_file2)
38
+ if File.extname(input_file2) == ".wta"
39
+ fl = WTBFile::new(File::new(input_file2, "rb"), true, File::new(input_file2.gsub(/wta\z/,"wtp"), "rb"))
40
+ else
41
+ fl = WTBFile::new(File::new(input_file2, "rb"))
42
+ end
43
+ Dir.mkdir("tex_output") unless Dir.exist?("tex_output")
44
+ prefix = File.join("tex_output", File.basename(input_file2, ".wtb"))
45
+ texs = fl.each.each_with_index.collect { |info_f, i|
46
+ info, f = info_f
47
+ ext, flags, idx = info
48
+ tex_name = "#{prefix}_#{"%03d"%i}#{ext}"
49
+ File::open(tex_name, "wb") { |f2|
50
+ f.rewind
51
+ f2.write(f.read)
52
+ }
53
+ [tex_name, [flags, idx]]
54
+ }
55
+
56
+ tex_conv_path = which("TexConv2.exe")
57
+ if !tex_conv_path
58
+ tex_conv_path = File.join(".", "TexConv2.exe")
59
+ if (!File.exist?(tex_conv_path))
60
+ tex_conv_path = File.join(File.expand_path(File.join(File.dirname(__FILE__), *[".."]*3)), "TexConv2.exe")
61
+ if (!File.exist?(tex_conv_path))
62
+ tex_conv_path = nil
63
+ end
64
+ end
65
+ end
66
+
67
+ fl2 = WTBFile::new
68
+ fl2.unknown = fl.unknown
69
+
70
+ fl0.each { |info, f|
71
+ ext, flags, idx = info
72
+ fl2.push( f, flags, idx )
73
+ }
74
+
75
+ texs.each { |name, info|
76
+ flags, idx = info
77
+ if File.extname(input_file2) == ".wta"
78
+ flags &= 0xffffffdf #remove 0x20 flag
79
+ if flags == 0x70000000
80
+ flags = 0x10000000
81
+ else
82
+ flags = 0x20000000
83
+ end
84
+ elsif fl.big
85
+ flags &= 0xfffffffd #remove 0x2 flag
86
+ end
87
+ if File.extname(name) == ".gtx"
88
+ new_name = name.gsub("gtx","dds")
89
+ raise "could not locate TexConv2.exe, put it in your PATH" unless tex_conv_path
90
+ res = `#{Shellwords.escape tex_conv_path} -i #{Shellwords.escape name} -o #{Shellwords.escape new_name}`
91
+ raise "could not execute TexConv2.exe:\n#{res}" if !$?.success?
92
+ else
93
+ new_name = name
94
+ end
95
+ fl2.push( File::new(new_name, "rb"), flags, nil )
96
+ }
97
+
98
+ if $options[:overwrite]
99
+ fl2.dump(input_file1)
100
+ else
101
+ Dir.mkdir("wtb_output") unless Dir.exist?("wtb_output")
102
+ fl2.dump(File.join("wtb_output", File.basename(input_file1)))
103
+ end
@@ -0,0 +1,69 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+ require_relative '../../bayonetta'
4
+ include Bayonetta
5
+
6
+ $options = {
7
+ output: nil
8
+ }
9
+ OptionParser.new do |opts|
10
+ opts.banner = <<EOF
11
+ Usage: wtx_creator target_directory
12
+ EOF
13
+ opts.on("-h", "--help", "Prints this help") do
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.on("-o", "--output=filename", "file to output result") do |name|
19
+ $options[:output] = name
20
+ end
21
+
22
+ end.parse!
23
+
24
+ input_dir = ARGV[0]
25
+
26
+ raise "Not a directory: #{input_dir}!" unless input_dir && File.directory?(input_dir)
27
+
28
+ files = Dir.entries(input_dir)
29
+ pwd = Dir.pwd
30
+ Dir.chdir(input_dir)
31
+ files.select! { |f| File.file?(f) && [".gtx", ".dds", ".bntx", ".xt1"].include?( File.extname(f) ) }
32
+ files.sort!
33
+ puts files
34
+ files.collect! { |fname| File::new(fname, "rb") }
35
+
36
+ big = false
37
+ big = YAML::load_file(".metadata/big.yaml") if File.exist?(".metadata/big.yaml")
38
+ extension = ".wtb"
39
+ extension = YAML::load_file(".metadata/extension.yaml") if File.exist?(".metadata/extension.yaml")
40
+ flags = []
41
+ flags = YAML::load_file(".metadata/texture_flags.yaml") if File.exist?(".metadata/texture_flags.yaml")
42
+ idx = []
43
+ idx = YAML::load_file(".metadata/texture_idx.yaml") if File.exist?(".metadata/texture_idx.yaml")
44
+ infos = []
45
+ infos = YAML::load_file(".metadata/texture_infos.yaml") if File.exist?(".metadata/texture_infos.yaml")
46
+ unknown = 0
47
+ unknown = YAML::load_file(".metadata/unknown.yaml") if File.exist?(".metadata/unknown.yaml")
48
+
49
+
50
+ wtb = WTBFile::new(nil, big, extension == ".wta")
51
+ files.each { |f|
52
+ wtb.push(f)
53
+ }
54
+ wtb.texture_flags = flags
55
+ wtb.texture_infos = infos
56
+ wtb.texture_idx = idx
57
+ wtb.unknown = unknown
58
+
59
+ output_file = $options[:output]
60
+ if !output_file
61
+ Dir.mkdir("wtx_output") unless Dir.exist?("wtx_output")
62
+ Dir.chdir("wtx_output")
63
+ output_file = File.basename(ARGV[0]).gsub("_wta","").gsub("_wtb", "") << extension
64
+ else
65
+ Dir.chdir(pwd)
66
+ end
67
+
68
+ wtb.dump(output_file)
69
+
@@ -0,0 +1,85 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+ require_relative '../../bayonetta'
4
+
5
+ $options = {
6
+ output: nil
7
+ }
8
+
9
+ OptionParser.new do |opts|
10
+ opts.banner = <<EOF
11
+ Usage: wtx_extractor file [wtp_file]
12
+ EOF
13
+ opts.on("-h", "--help", "Prints this help") do
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.on("-o", "--output=dirname", "directory to output result") do |name|
19
+ $options[:output] = name
20
+ end
21
+
22
+ end.parse!
23
+
24
+ save_pwd = Dir.pwd
25
+
26
+ filename = ARGV[0]
27
+ raise "Invalid file: #{filename}!" unless filename && File.exist?(filename)
28
+ wtp_name = ARGV[1]
29
+ raise "Invalid file: #{filename}!" if wtp_name && !File.exist?(wtp_name)
30
+
31
+ directory = File.dirname(filename)
32
+ name = File.basename(filename)
33
+ ext_name = File.extname(name)
34
+
35
+ raise "Invalid file: #{filename}!" unless ext_name == ".wta" || ext_name == ".wtb"
36
+
37
+ f = File::open(filename, "rb")
38
+
39
+ Dir.chdir(directory)
40
+ tex_name = File.basename(name, ext_name)
41
+ if ext_name == ".wta"
42
+ wtp_name = tex_name + ".wtp" unless wtp_name
43
+ f_wtp = File::open(wtp_name, "rb")
44
+ dir_name = tex_name + "_wta"
45
+ else
46
+ f_wtp = nil
47
+ dir_name = tex_name + "_wtb"
48
+ end
49
+ if $options[:output]
50
+ Dir.chdir(save_pwd)
51
+ Dir.chdir($options[:output])
52
+ end
53
+ Dir.mkdir(dir_name) unless Dir.exist?(dir_name)
54
+ Dir.chdir(dir_name)
55
+
56
+ wtb = Bayonetta::WTBFile::new(f, true, f_wtp)
57
+
58
+ wtb.each.each_with_index { |info_f, i|
59
+ info, f = info_f
60
+ ext, _, _ = info
61
+ File::open("#{tex_name}_#{"%03d"%i}#{ext}", "wb") { |f2|
62
+ f.rewind
63
+ f2.write(f.read)
64
+ }
65
+ }
66
+ Dir.mkdir(".metadata") unless Dir.exist?(".metadata")
67
+ Dir.chdir(".metadata")
68
+ File::open("texture_flags.yaml", "w") { |fl|
69
+ fl.print YAML::dump( wtb.texture_flags )
70
+ }
71
+ File::open("texture_idx.yaml", "w") { |fl|
72
+ fl.print YAML::dump( wtb.texture_idx )
73
+ }
74
+ File::open("texture_infos.yaml", "w") { |fl|
75
+ fl.print YAML::dump( wtb.texture_infos )
76
+ }
77
+ File::open("big.yaml","w") { |fl|
78
+ fl.print YAML::dump( wtb.big )
79
+ }
80
+ File::open("unknown.yaml","w") { |fl|
81
+ fl.print YAML::dump( wtb.unknown )
82
+ }
83
+ File::open("extension.yaml", "w") { |fl|
84
+ fl.print YAML::dump( ext_name )
85
+ }