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,759 +1,759 @@
1
- module Bayonetta
2
- class WMB3File < LibBin::Structure
3
- include Alignment
4
-
5
- class MeshMaterialPair < LibBin::Structure
6
- uint32 :mesh_index
7
- uint32 :material_index
8
- end
9
-
10
- class Mesh < LibBin::Structure
11
- class Header < LibBin::Structure
12
- uint32 :offset_name
13
- float :bounding_box, length: 6
14
- uint32 :offset_materials
15
- uint32 :num_materials
16
- uint32 :offset_bones_indices
17
- uint32 :num_bones_indices
18
- end
19
- register_field :header, Header
20
- string :name, offset: 'header\offset_name'
21
- uint16 :materials, length: 'header\num_materials', offset: 'header\offset_materials'
22
- uint16 :bone_indices, length: 'header\num_bones_indices', offset: 'header\offset_bones_indices'
23
- end
24
-
25
- class Material < LibBin::Structure
26
-
27
- class Variable < LibBin::Structure
28
- uint32 :offset_name
29
- float :value
30
- string :name, offset: 'offset_name'
31
- end
32
-
33
- class ParameterGroup < LibBin::Structure
34
- int32 :index
35
- uint32 :offset_parameters
36
- uint32 :num_parameters
37
- float :parameters, length: 'num_parameters', offset: 'offset_parameters'
38
- end
39
-
40
- class Texture < LibBin::Structure
41
- uint32 :offset_name
42
- uint32 :texture_id
43
- string :name, offset: 'offset_name'
44
- end
45
-
46
- class Header < LibBin::Structure
47
- uint16 :date, length: 4
48
- uint32 :offset_name
49
- uint32 :offset_shader_name
50
- uint32 :offset_technique_name
51
- uint32 :u_a
52
- uint32 :offset_textures
53
- uint32 :num_textures
54
- uint32 :offset_parameters_groups
55
- uint32 :num_parameters_groups
56
- uint32 :offset_variables
57
- uint32 :num_variables
58
- end
59
- register_field :header, Header
60
- string :name, offset: 'header\offset_name'
61
- string :shader_name, offset: 'header\offset_shader_name'
62
- string :technique_name, offset: 'header\offset_technique_name'
63
- register_field :textures, Texture, count: 'header\num_textures', sequence: true,
64
- offset: 'header\offset_textures + __iterator * 8'
65
- register_field :parameters_groups, ParameterGroup, count: 'header\num_parameters_groups',
66
- sequence: true, offset: 'header\offset_parameters_groups + __iterator * 12'
67
- register_field :variables, Variable, count: 'header\num_variables', sequence: true,
68
- offset: 'header\offset_variables + __iterator * 8'
69
-
70
- end
71
-
72
- class BoneSet < LibBin::Structure
73
- uint32 :offset_bone_indices
74
- uint32 :num_bone_indices
75
- int16 :bone_indices, length: 'num_bone_indices', offset: 'offset_bone_indices'
76
- end
77
-
78
- class Lod < LibBin::Structure
79
-
80
- class BatchInfo < LibBin::Structure
81
- uint32 :vertex_group_index
82
- uint32 :mesh_index
83
- uint32 :material_index
84
- int32 :call_tree_node_index
85
- uint32 :mesh_material_index
86
- int32 :u_b
87
- end
88
-
89
- class Header < LibBin::Structure
90
- uint32 :offset_name
91
- int32 :lod_level
92
- uint32 :batch_start
93
- uint32 :offset_batch_infos
94
- uint32 :num_batch_infos
95
- end
96
- register_field :header, Header
97
- string :name, offset: 'header\offset_name'
98
- register_field :batch_infos, BatchInfo, length: 'header\num_batch_infos', offset: 'header\offset_batch_infos'
99
- end
100
-
101
- class ColTreeNode < LibBin::Structure
102
- register_field :p1, Position
103
- register_field :p2, Position
104
- int32 :left
105
- int32 :right
106
- end
107
-
108
- class Batch < LibBin::Structure
109
- uint32 :vertex_group_index
110
- int32 :bone_set_index
111
- uint32 :vertex_start
112
- uint32 :index_start
113
- uint32 :num_vertexes
114
- uint32 :num_indices
115
- uint32 :num_primitives
116
- end
117
-
118
- VERTEX_TYPES = {}
119
- VERTEX_TYPES.update( YAML::load_file(File.join( File.dirname(__FILE__), 'vertex_types_nier.yaml')) )
120
-
121
- class VertexGroup < LibBin::Structure
122
-
123
- def is_bayo2? #UByteList are arrays of char really
124
- true
125
- end
126
-
127
- def get_vertex_fields
128
- if @vertex_fields
129
- return @vertex_fields
130
- else
131
- types = VERTEX_TYPES[ @header.vertex_flags ]
132
- @vertex_fields = []
133
- if types[0]
134
- types[0].each { |name, type|
135
- @vertex_fields.push(name)
136
- }
137
- end
138
- if types[1]
139
- types[1].each { |name, type|
140
- @vertex_fields.push(name)
141
- }
142
- end
143
- return @vertex_fields
144
- end
145
- end
146
-
147
- def get_vertex_types
148
- if @vertex_type
149
- return [@vertex_type, @vertex_ex_type]
150
- else
151
- types = VERTEX_TYPES[ @header.vertex_flags ]
152
- @vertex_type = Class::new(LibBin::Structure)
153
- @vertex_size = 0
154
- if types[0]
155
- types[0].each { |name, type|
156
- @vertex_type.register_field(name, VERTEX_FIELDS[type][0])
157
- @vertex_size += VERTEX_FIELDS[type][1]
158
- }
159
- end
160
- raise "Invalid size for vertex data #{@vertex_size} != #{@header.vertex_size}!" if @vertex_size != @header.vertex_size
161
- @vertex_ex_type = Class::new(LibBin::Structure)
162
- @vertex_ex_size = 0
163
- if types[1]
164
- types[1].each { |name, type|
165
- @vertex_ex_type.register_field(name, VERTEX_FIELDS[type][0])
166
- @vertex_ex_size += VERTEX_FIELDS[type][1]
167
- }
168
- end
169
- raise "Invalid size for ex data #{@vertex_ex_size} != #{@header.vertex_ex_data_size}!" if @vertex_ex_size != @header.vertex_ex_data_size
170
- return [@vertex_type, @vertex_ex_type]
171
- end
172
- end
173
-
174
- def get_vertex_field(field, vi)
175
- if @vertexes[vi].respond_to?(field)
176
- return @vertexes[vi].send(field)
177
- elsif @vertexes_ex_data && @vertexes_ex_data[vi].respond_to?(field)
178
- return @vertexes_ex_data[vi].send(field)
179
- else
180
- return nil
181
- end
182
- end
183
-
184
- def set_vertex_field(field, vi, val)
185
- if @vertexes[vi].respond_to?(field)
186
- return @vertexes[vi].send(:"#{field}=", val)
187
- elsif @vertexes_ex_data && @vertexes_ex_data[vi].respond_to?(field)
188
- return @vertexes_ex_data[vi].send(:"#{field}=", val)
189
- else
190
- raise "Couldn't find field: #{field}!"
191
- end
192
- end
193
-
194
- class Header < LibBin::Structure
195
- uint32 :offset_vertexes
196
- uint32 :offset_vertexes_ex_data
197
- uint32 :u_a
198
- uint32 :u_b
199
- uint32 :vertex_size
200
- uint32 :vertex_ex_data_size
201
- uint32 :u_c
202
- uint32 :u_d
203
- uint32 :num_vertexes
204
- uint32 :vertex_flags
205
- uint32 :offset_indices
206
- uint32 :num_indices
207
- end
208
- register_field :header, Header
209
- register_field :vertexes, 'get_vertex_types[0]', length: 'header\num_vertexes', offset: 'header\offset_vertexes'
210
- register_field :vertexes_ex_data, 'get_vertex_types[1]', length: 'header\num_vertexes',
211
- offset: 'header\offset_vertexes_ex_data'
212
- register_field :indices, '(..\header.flags & 0x8) != 0 ? UInt32 : UInt16' , length: 'header\num_indices', offset: 'header\offset_indices'
213
- end
214
-
215
- class Bone < LibBin::Structure
216
- int16 :id
217
- int16 :parent_index
218
- register_field :local_position, Position
219
- register_field :local_rotation, Position
220
- register_field :local_scale, Position
221
- register_field :position, Position
222
- register_field :rotation, Position
223
- register_field :scale, Position
224
- register_field :t_position, Position
225
- end
226
-
227
- class Unknown1 < LibBin::Structure
228
- uint32 :data, length: 6
229
- end
230
-
231
- class InfoPair < LibBin::Structure
232
- uint32 :offset
233
- uint32 :number
234
- end
235
-
236
- class Header < LibBin::Structure
237
- def self.info_pair(field, length: nil, count: nil, offset: nil, sequence: false, condition: nil)
238
- register_field(field, InfoPair, length: length, count: count, offset: offset, sequence: sequence, condition: condition)
239
- end
240
-
241
- uint32 :id
242
- uint32 :version
243
- int32 :u_a
244
- int16 :flags
245
- int16 :u_c
246
- float :bounding_box, length: 6
247
- info_pair :info_bones
248
- info_pair :info_bone_index_translate_table
249
- info_pair :info_vertex_groups
250
- info_pair :info_batches
251
- info_pair :info_lods
252
- info_pair :info_col_tree_nodes
253
- info_pair :info_bone_map
254
- info_pair :info_bone_sets
255
- info_pair :info_materials
256
- info_pair :info_meshes
257
- info_pair :info_mesh_material_pairs
258
- info_pair :info_unknown1
259
- end
260
-
261
- register_field :header, Header
262
- register_field :bones, Bone, length: 'header\info_bones\number',
263
- offset: 'header\info_bones\offset'
264
- register_field :bone_index_translate_table, BoneIndexTranslateTable,
265
- offset: 'header\info_bone_index_translate_table\offset'
266
- register_field :vertex_groups, VertexGroup, count: 'header\info_vertex_groups\number',
267
- sequence: true, offset: 'header\info_vertex_groups\offset + __iterator * 48'
268
- register_field :batches, Batch, length: 'header\info_batches\number',
269
- offset: 'header\info_batches\offset'
270
- register_field :lods, Lod, count: 'header\info_lods\number', sequence: true,
271
- offset: 'header\info_lods\offset + __iterator * 20'
272
- register_field :col_tree_nodes, ColTreeNode, length: 'header\info_col_tree_nodes\number',
273
- offset: 'header\info_col_tree_nodes\offset'
274
- uint32 :bone_map, length: 'header\info_bone_map\number',
275
- offset: 'header\info_bone_map\offset'
276
- register_field :bone_sets, BoneSet, count: 'header\info_bone_sets\number', sequence: true,
277
- offset: 'header\info_bone_sets\offset + __iterator * 8'
278
- register_field :materials, Material, count: 'header\info_materials\number', sequence: true,
279
- offset: 'header\info_materials\offset + __iterator * 48'
280
- register_field :meshes, Mesh, count: 'header\info_meshes\number', sequence: true,
281
- offset: 'header\info_meshes\offset + __iterator * 44'
282
- register_field :mesh_material_pairs, MeshMaterialPair,
283
- length: 'header\info_mesh_material_pairs\number',
284
- offset: 'header\info_mesh_material_pairs\offset'
285
- register_field :unknown1, Unknown1, length: 'header\info_unknown1\number',
286
- offset: 'header\info_unknown1\offset'
287
-
288
- def texture_ids
289
- ids = @materials.collect { |m|
290
- m.textures.collect { |t| t.texture_id }
291
- }
292
- ids.flatten.uniq
293
- end
294
-
295
- def materials_textures
296
- mat_tex = @materials.collect { |m|
297
- [m.name, m.textures.collect { |t| [t.texture_id, t.name] }]
298
- }.to_h
299
- end
300
-
301
- def cleanup_vertexes
302
- vertex_usage, index_usage = get_vertex_index_usage
303
- @vertex_groups.each_with_index { |vertex_group, vertex_group_index|
304
- new_vertex_map = vertex_usage[vertex_group_index].uniq.sort.each_with_index.to_h
305
- vertex_group.vertexes = new_vertex_map.keys.collect { |i|
306
- vertex_group.vertexes[i]
307
- }
308
- vertex_group.vertexes_ex_data = new_vertex_map.keys.collect { |i|
309
- vertex_group.vertexes_ex_data[i]
310
- }
311
- vertex_group.header.num_vertexes = vertex_group.vertexes.size
312
-
313
- new_index_map = index_usage[vertex_group_index].uniq.sort.each_with_index.to_h
314
- vertex_group.indices = new_index_map.keys.collect { |i|
315
- new_vertex_map[vertex_group.indices[i]]
316
- }
317
- vertex_group.header.num_indices = vertex_group.indices.size
318
- @batches.select { |batch| batch.vertex_group_index == vertex_group_index }.each { |batch|
319
- batch.vertex_start = new_vertex_map[batch.vertex_start]
320
- batch.index_start = new_index_map[batch.index_start]
321
- if batch.vertex_start != 0
322
- ((batch.index_start)...(batch.index_start + batch.num_indices)).each { |i|
323
- vertex_group.indices[i] = vertex_group.indices[i] - batch.vertex_start
324
- }
325
- end
326
- }
327
- }
328
- end
329
-
330
- def get_vertex_index_usage
331
- vertex_usage = Hash::new { |h, k| h[k] = [] }
332
- index_usage = Hash::new { |h, k| h[k] = [] }
333
- @batches.each { |batch|
334
- index_range = (batch.index_start)...(batch.index_start + batch.num_indices)
335
- index_usage[batch.vertex_group_index] += index_range.to_a
336
- vertex_usage[batch.vertex_group_index] += @vertex_groups[batch.vertex_group_index].indices[index_range].collect { |vertex|
337
- vertex + batch.vertex_start
338
- }
339
- }
340
- return [vertex_usage, index_usage]
341
- end
342
-
343
- def delete_meshes(list)
344
- kept_meshes = @meshes.size.times.to_a - list
345
- new_mesh_map = kept_meshes.each_with_index.to_h
346
- if @meshes
347
- @meshes = kept_meshes.collect { |i|
348
- @meshes[i]
349
- }
350
- @header.info_meshes.number = @meshes.size
351
- end
352
- if @mesh_material_pairs
353
- @mesh_material_pairs = @mesh_material_pairs.select { |pair|
354
- ! list.include?(pair.mesh_index)
355
- }
356
- @header.info_mesh_material_pairs.number = @mesh_material_pairs.size
357
- @mesh_material_pairs.each { |pair|
358
- pair.mesh_index = new_mesh_map[pair.mesh_index]
359
- }
360
- end
361
- if @lods && @batches
362
- batch_indexes = @header.info_batches.number.times.to_a
363
- filtered_batches = Set::new
364
- @lods.each { |lod|
365
- if lod.batch_infos
366
- lod.batch_infos.each_with_index { |batch_info, index|
367
- if list.include?(batch_info.mesh_index)
368
- filtered_batches.add( index + lod.header.batch_start )
369
- end
370
- }
371
- lod.batch_infos = lod.batch_infos.select { |batch_info|
372
- ! list.include?(batch_info.mesh_index)
373
- }
374
- lod.header.num_batch_infos = lod.batch_infos.size
375
- lod.batch_infos.each { |batch_info|
376
- batch_info.mesh_index = new_mesh_map[batch_info.mesh_index]
377
- }
378
- end
379
- }
380
- batch_indexes -= filtered_batches.to_a
381
- batch_index_map = batch_indexes.each_with_index.to_h
382
- @batches = batch_indexes.collect { |index|
383
- @batches[index]
384
- }
385
- @header.info_batches.number = @batches.size
386
- @lods.each { |lod|
387
- if lod.batch_infos
388
- lod.header.batch_start = batch_index_map[lod.header.batch_start]
389
- end
390
- }
391
- end
392
- self
393
- end
394
-
395
- def delete_batches(batch_list)
396
- if @lods && @batches
397
- batch_indexes = @header.info_batches.number.times.to_a
398
- batch_indexes -= batch_list
399
- batch_index_map = batch_indexes.each_with_index.to_h
400
- @batches = batch_indexes.collect { |index|
401
- @batches[index]
402
- }
403
- @header.info_batches.number = @batches.size
404
- @lods.each { |lod|
405
- if lod.batch_infos
406
- new_batch_infos = []
407
- lod.batch_infos.each_with_index { |batch_info, index|
408
- unless batch_list.include?(lod.header.batch_start + index)
409
- new_batch_infos.push batch_info
410
- end
411
- lod.batch_infos = new_batch_infos
412
- lod.header.num_batch_infos = lod.batch_infos.size
413
- }
414
- end
415
- }
416
- @lods.each { |lod|
417
- if lod.batch_infos
418
- lod.header.batch_start = batch_index_map[lod.header.batch_start]
419
- end
420
- }
421
- end
422
- end
423
-
424
- def recompute_layout
425
- last_offset = 0x88
426
-
427
- if @header.info_bones.number > 0
428
- last_offset = @header.info_bones.offset = align(last_offset, 0x10)
429
- last_offset += @bones.first.__size * @header.info_bones.number
430
- else
431
- @header.info_bones.offset = 0x0
432
- end
433
-
434
- if @header.info_bones.number > 0
435
- last_offset = @header.info_bone_index_translate_table.offset = align(last_offset, 0x10)
436
- last_offset += @bone_index_translate_table.__size
437
- else
438
- @header.info_bone_index_translate_table.offset = 0x0
439
- end
440
-
441
- if @header.info_vertex_groups.number > 0
442
- last_offset = @header.info_vertex_groups.offset = align(last_offset, 0x4)
443
- last_offset += @vertex_groups.first.header.__size * @header.info_vertex_groups.number
444
- @vertex_groups.each { |vg|
445
- if vg.header.num_vertexes > 0
446
- last_offset = vg.header.offset_vertexes = align(last_offset, 0x10)
447
- last_offset += vg.header.vertex_size * vg.header.num_vertexes
448
- if vg.header.vertex_ex_data_size > 0
449
- last_offset = vg.header.offset_vertexes_ex_data = align(last_offset, 0x10)
450
- last_offset += vg.header.vertex_ex_data_size * vg.header.num_vertexes
451
- end
452
- end
453
- if vg.header.num_indices > 0
454
- last_offset = vg.header.offset_indices = align(last_offset, 0x10)
455
- last_offset += (@header.flags & 0x8 > 0 ? 4 : 2) * vg.header.num_indices
456
- end
457
- }
458
- else
459
- @header.info_vertex_groups.offset = 0x0
460
- end
461
-
462
- if @header.info_batches.number > 0
463
- last_offset = @header.info_batches.offset = align(last_offset, 0x4)
464
- last_offset += @batches.first.__size * @header.info_batches.number
465
- else
466
- @header.info_batches.offset = 0x0
467
- end
468
-
469
- if @header.info_lods.number > 0
470
- last_offset = @header.info_lods.offset = align(last_offset, 0x4)
471
- last_offset += @lods.first.header.__size * @header.info_lods.number
472
- @lods.each { |lod|
473
- if lod.header.num_batch_infos > 0
474
- lod.header.offset_batch_infos = last_offset
475
- last_offset += lod.batch_infos.first.__size * lod.header.num_batch_infos
476
- end
477
- lod.header.offset_name = last_offset
478
- last_offset += lod.name.size
479
- }
480
- else
481
- @header.info_lods.offset = 0x0
482
- end
483
-
484
- if @header.info_mesh_material_pairs.number > 0
485
- last_offset = @header.info_mesh_material_pairs.offset = align(last_offset, 0x10)
486
- last_offset += @mesh_material_pairs.first.__size * @header.info_mesh_material_pairs.number
487
- else
488
- @header.info_mesh_material_pairs.offset = 0x0
489
- end
490
-
491
- if @header.info_col_tree_nodes.number > 0
492
- last_offset = @header.info_col_tree_nodes.offset = align(last_offset, 0x10)
493
- last_offset += @col_tree_nodes.first.__size * @header.info_col_tree_nodes.number
494
- else
495
- @header.info_col_tree_nodes.offset = 0x0
496
- end
497
-
498
- if @header.info_bone_sets.number > 0
499
- last_offset = @header.info_bone_sets.offset = align(last_offset, 0x10)
500
- last_offset += 0x8 * @header.info_bone_sets.number
501
- @bone_sets.each { |bone_set|
502
- last_offset = bone_set.offset_bone_indices = align(last_offset, 0x10)
503
- last_offset += 0x2 * bone_set.num_bone_indices
504
- }
505
- else
506
- @header.info_bone_sets.offset = 0x0
507
- end
508
-
509
- if @header.info_bone_map.number > 0
510
- last_offset = @header.info_bone_map.offset = align(last_offset, 0x10)
511
- last_offset += 0x4 * @header.info_bone_map.number
512
- else
513
- @header.info_bone_map.offset = 0x0
514
- end
515
-
516
- if @header.info_meshes.number > 0
517
- last_offset = @header.info_meshes.offset = align(last_offset, 0x4)
518
- last_offset += @meshes.first.header.__size * @header.info_meshes.number
519
- @meshes.each { |mesh|
520
- mesh.header.offset_name = last_offset
521
- last_offset += mesh.name.size
522
- if mesh.header.num_materials > 0
523
- mesh.header.offset_materials = last_offset
524
- last_offset += 0x2 * mesh.header.num_materials
525
- else
526
- mesh.header.offset_materials = 0x0
527
- end
528
- if mesh.header.num_bones_indices > 0
529
- mesh.header.offset_bones_indices = last_offset
530
- last_offset += 0x2 * mesh.header.num_bones_indices
531
- else
532
- mesh.header.offset_bones_indices = 0x0
533
- end
534
- }
535
- else
536
- @header.info_meshes.offset = 0x0
537
- end
538
-
539
- if @header.info_materials.number > 0
540
- last_offset = @header.info_materials.offset = align(last_offset, 0x10)
541
- last_offset += @materials.first.header.__size * @header.info_materials.number
542
- @materials.each { |material|
543
- material.header.offset_name = last_offset
544
- last_offset += material.name.size
545
- material.header.offset_shader_name = last_offset
546
- last_offset += material.shader_name.size
547
- material.header.offset_technique_name = last_offset
548
- last_offset += material.technique_name.size
549
- if material.header.num_textures > 0
550
- material.header.offset_textures = last_offset
551
- last_offset += 0x8 * material.header.num_textures
552
- material.textures.each { |texture|
553
- texture.offset_name = last_offset
554
- last_offset += texture.name.size
555
- }
556
- else
557
- material.header.offset_textures = 0x0
558
- end
559
- if material.header.num_parameters_groups > 0
560
- last_offset = material.header.offset_parameters_groups = align(last_offset, 0x10)
561
- last_offset += 0xC * material.header.num_parameters_groups
562
- material.parameters_groups.each { |parameter_group|
563
- last_offset = parameter_group.offset_parameters = align(last_offset, 0x10)
564
- last_offset += 0x4 * parameter_group.num_parameters
565
- }
566
- else
567
- material.header.offset_parameters_group = 0x0
568
- end
569
- if material.header.num_variables > 0
570
- last_offset = material.header.offset_variables = align(last_offset, 0x10)
571
- last_offset += 0x8 * material.header.num_variables
572
- material.variables.each { |variable|
573
- variable.offset_name = last_offset
574
- last_offset += variable.name.size
575
- }
576
- else
577
- material.header.offset_variables = 0x0
578
- end
579
- }
580
- else
581
- @header.info_materials.offset = 0x0
582
- end
583
-
584
- if @header.info_unknown1.number > 0
585
- last_offset = @header.info_unknown1.offset = align(last_offset, 0x4)
586
- last_offset += @unknown1.first.__size * @header.info_unknown1.number
587
- else
588
- @header.info_unknown1.offset = 0x0
589
- end
590
-
591
- end
592
-
593
- def was_big?
594
- @__was_big
595
- end
596
-
597
- def get_vertex_field(field, vg, vi)
598
- @vertex_groups[vg].get_vertex_field(field, vi)
599
- end
600
-
601
- def set_vertex_field(field, vg, vi, val)
602
- @vertex_groups[vg].set_vertex_field(field, vi, val)
603
- end
604
-
605
- def scale(s)
606
- @vertex_groups.each { |vg|
607
- if vg.vertexes && vg.vertexes.first.respond_to?(:position)
608
- vg.vertexes.each { |v|
609
- v.position.x = v.position.x * s
610
- v.position.y = v.position.y * s
611
- v.position.z = v.position.z * s
612
- }
613
- end
614
- }
615
- @bones.each { |b|
616
- b.position.x = b.position.x * s
617
- b.position.y = b.position.y * s
618
- b.position.z = b.position.z * s
619
- b.local_position.x = b.local_position.x * s
620
- b.local_position.y = b.local_position.y * s
621
- b.local_position.z = b.local_position.z * s
622
- b.t_position.x = b.t_position.x * s
623
- b.t_position.y = b.t_position.y * s
624
- b.t_position.z = b.t_position.z * s
625
- }
626
- self
627
- end
628
-
629
- def dump_bones(list = nil)
630
- bone_struct = Struct::new(:index, :parent, :relative_position, :position, :global_index, :symmetric, :flag)
631
- list = (0...@header.num_bones) unless list
632
- list.collect { |bi|
633
- bone_struct::new(bi, @bones[bi].parent_index, @bones[bi].local_position, @bones[bi].position,
634
- @bones[bi].id, -1, 5)
635
- }
636
- end
637
-
638
- def get_vertex_usage
639
- vertex_usage = Hash::new { |h, k| h[k] = [] }
640
- @batches.each { |b|
641
- @vertex_groups[b.vertex_group_index].indices[b.index_start...(b.index_start+b.num_indices)].each { |i|
642
- vertex_usage[[b.vertex_group_index, i]].push( b )
643
- }
644
- }
645
- vertex_usage.each { |k,v| v.uniq! }
646
- vertex_usage
647
- end
648
-
649
- def recompute_relative_positions
650
- @bones.each { |b|
651
- if b.parent_index != -1
652
- b.local_position = b.position - @bones[b.parent_index].position
653
- else
654
- b.local_position = b.position
655
- end
656
- }
657
- self
658
- end
659
-
660
- def set_tpose
661
- neutral_scale = Linalg::Vector::new(1.0, 1.0, 1.0)
662
- inverse_bind_pose = @bones.collect { |b|
663
- parent_scale = neutral_scale
664
- parent_scale = @bones[b.parent_index].scale if b.parent_index != -1
665
- Linalg::get_inverse_transformation_matrix(b.position, b.rotation, b.scale, parent_scale)
666
- }
667
- target_pose = @bones.collect { |b|
668
- Linalg::get_translation_matrix(b.t_position)
669
- }
670
- bones.each { |b|
671
- b.position = b.t_position
672
- b.rotation.x = 0.0
673
- b.rotation.y = 0.0
674
- b.rotation.z = 0.0
675
- b.scale.x = 1.0
676
- b.scale.y = 1.0
677
- b.scale.z = 1.0
678
- b.local_rotation.x = 0.0
679
- b.local_rotation.y = 0.0
680
- b.local_rotation.z = 0.0
681
- b.local_scale.x = 1.0
682
- b.local_scale.y = 1.0
683
- b.local_scale.z = 1.0
684
- }
685
- multiplied_matrices = target_pose.each_with_index.collect { |m, i|
686
- m * inverse_bind_pose[i]
687
- }
688
- vertex_usage = get_vertex_usage
689
- vertex_usage.each { |(vgi, vi), bs|
690
- if bs.first.bone_set_index >= 0
691
- bone_set = bone_sets[bs.first.bone_set_index].bone_indices
692
- bone_refs = bone_set.collect { |bi| @bone_map[bi] }
693
- else
694
- bone_refs = @bone_map
695
- end
696
- bone_infos = get_vertex_field(:bone_infos, vgi, vi)
697
- indexes_and_weights = bone_infos.get_indexes_and_weights
698
- vertex_matrix = Linalg::get_zero_matrix
699
- indexes_and_weights.each { |bi, bw|
700
- i = bone_refs[bi]
701
- vertex_matrix = vertex_matrix + multiplied_matrices[i] * (bw.to_f/255.to_f)
702
- }
703
- vp = get_vertex_field(:position, vgi, vi)
704
- new_vp = vertex_matrix * Linalg::Vector::new(vp.x, vp.y, vp.z)
705
- vp.x = new_vp.x
706
- vp.y = new_vp.y
707
- vp.z = new_vp.z
708
- n = get_vertex_field(:normal, vgi, vi)
709
- new_n = vertex_matrix * Linalg::Vector::new(n.x, n.y, n.z, 0.0)
710
- n.x = new_n.x
711
- n.y = new_n.y
712
- n.z = new_n.z
713
- t = get_vertex_field(:tangents, vgi, vi)
714
- new_t = vertex_matrix * Linalg::Vector::new(t.x, t.y, t.z, 0.0)
715
- t.x = new_t.x
716
- t.y = new_t.y
717
- t.z = new_t.z
718
- }
719
- self
720
- end
721
-
722
- def self.load(input_name)
723
- if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
724
- input = input_name
725
- else
726
- File.open(input_name, "rb") { |f|
727
- input = StringIO::new(f.read, "rb")
728
- }
729
- end
730
- wmb = self::new
731
- wmb.instance_variable_set(:@__was_big, false)
732
- wmb.__load(input, false)
733
- input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
734
- wmb
735
- end
736
-
737
- def dump(output_name, output_big = false)
738
- if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
739
- output = output_name
740
- else
741
- output = StringIO::new("", "wb")#File.open(output_name, "wb")
742
- end
743
- output.rewind
744
-
745
- __set_dump_state(output, output_big, nil, nil)
746
- __dump_fields
747
- __unset_dump_state
748
-
749
-
750
- unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
751
- File.open(output_name, "wb") { |f|
752
- f.write output.string
753
- }
754
- output.close
755
- end
756
- self
757
- end
758
- end
759
- end
1
+ module Bayonetta
2
+ class WMB3File < LibBin::Structure
3
+ include Alignment
4
+
5
+ class MeshMaterialPair < LibBin::Structure
6
+ uint32 :mesh_index
7
+ uint32 :material_index
8
+ end
9
+
10
+ class Mesh < LibBin::Structure
11
+ class Header < LibBin::Structure
12
+ uint32 :offset_name
13
+ float :bounding_box, length: 6
14
+ uint32 :offset_materials
15
+ uint32 :num_materials
16
+ uint32 :offset_bones_indices
17
+ uint32 :num_bones_indices
18
+ end
19
+ register_field :header, Header
20
+ string :name, offset: 'header\offset_name'
21
+ uint16 :materials, length: 'header\num_materials', offset: 'header\offset_materials'
22
+ uint16 :bone_indices, length: 'header\num_bones_indices', offset: 'header\offset_bones_indices'
23
+ end
24
+
25
+ class Material < LibBin::Structure
26
+
27
+ class Variable < LibBin::Structure
28
+ uint32 :offset_name
29
+ float :value
30
+ string :name, offset: 'offset_name'
31
+ end
32
+
33
+ class ParameterGroup < LibBin::Structure
34
+ int32 :index
35
+ uint32 :offset_parameters
36
+ uint32 :num_parameters
37
+ float :parameters, length: 'num_parameters', offset: 'offset_parameters'
38
+ end
39
+
40
+ class Texture < LibBin::Structure
41
+ uint32 :offset_name
42
+ uint32 :texture_id
43
+ string :name, offset: 'offset_name'
44
+ end
45
+
46
+ class Header < LibBin::Structure
47
+ uint16 :date, length: 4
48
+ uint32 :offset_name
49
+ uint32 :offset_shader_name
50
+ uint32 :offset_technique_name
51
+ uint32 :u_a
52
+ uint32 :offset_textures
53
+ uint32 :num_textures
54
+ uint32 :offset_parameters_groups
55
+ uint32 :num_parameters_groups
56
+ uint32 :offset_variables
57
+ uint32 :num_variables
58
+ end
59
+ register_field :header, Header
60
+ string :name, offset: 'header\offset_name'
61
+ string :shader_name, offset: 'header\offset_shader_name'
62
+ string :technique_name, offset: 'header\offset_technique_name'
63
+ register_field :textures, Texture, count: 'header\num_textures', sequence: true,
64
+ offset: 'header\offset_textures + __iterator * 8'
65
+ register_field :parameters_groups, ParameterGroup, count: 'header\num_parameters_groups',
66
+ sequence: true, offset: 'header\offset_parameters_groups + __iterator * 12'
67
+ register_field :variables, Variable, count: 'header\num_variables', sequence: true,
68
+ offset: 'header\offset_variables + __iterator * 8'
69
+
70
+ end
71
+
72
+ class BoneSet < LibBin::Structure
73
+ uint32 :offset_bone_indices
74
+ uint32 :num_bone_indices
75
+ int16 :bone_indices, length: 'num_bone_indices', offset: 'offset_bone_indices'
76
+ end
77
+
78
+ class Lod < LibBin::Structure
79
+
80
+ class BatchInfo < LibBin::Structure
81
+ uint32 :vertex_group_index
82
+ uint32 :mesh_index
83
+ uint32 :material_index
84
+ int32 :call_tree_node_index
85
+ uint32 :mesh_material_index
86
+ int32 :u_b
87
+ end
88
+
89
+ class Header < LibBin::Structure
90
+ uint32 :offset_name
91
+ int32 :lod_level
92
+ uint32 :batch_start
93
+ uint32 :offset_batch_infos
94
+ uint32 :num_batch_infos
95
+ end
96
+ register_field :header, Header
97
+ string :name, offset: 'header\offset_name'
98
+ register_field :batch_infos, BatchInfo, length: 'header\num_batch_infos', offset: 'header\offset_batch_infos'
99
+ end
100
+
101
+ class ColTreeNode < LibBin::Structure
102
+ register_field :p1, Position
103
+ register_field :p2, Position
104
+ int32 :left
105
+ int32 :right
106
+ end
107
+
108
+ class Batch < LibBin::Structure
109
+ uint32 :vertex_group_index
110
+ int32 :bone_set_index
111
+ uint32 :vertex_start
112
+ uint32 :index_start
113
+ uint32 :num_vertexes
114
+ uint32 :num_indices
115
+ uint32 :num_primitives
116
+ end
117
+
118
+ VERTEX_TYPES = {}
119
+ VERTEX_TYPES.update( YAML::load_file(File.join( File.dirname(__FILE__), 'vertex_types_nier.yaml')) )
120
+
121
+ class VertexGroup < LibBin::Structure
122
+
123
+ def is_bayo2? #UByteList are arrays of char really
124
+ true
125
+ end
126
+
127
+ def get_vertex_fields
128
+ if @vertex_fields
129
+ return @vertex_fields
130
+ else
131
+ types = VERTEX_TYPES[ @header.vertex_flags ]
132
+ @vertex_fields = []
133
+ if types[0]
134
+ types[0].each { |name, type|
135
+ @vertex_fields.push(name)
136
+ }
137
+ end
138
+ if types[1]
139
+ types[1].each { |name, type|
140
+ @vertex_fields.push(name)
141
+ }
142
+ end
143
+ return @vertex_fields
144
+ end
145
+ end
146
+
147
+ def get_vertex_types
148
+ if @vertex_type
149
+ return [@vertex_type, @vertex_ex_type]
150
+ else
151
+ types = VERTEX_TYPES[ @header.vertex_flags ]
152
+ @vertex_type = Class::new(LibBin::Structure)
153
+ @vertex_size = 0
154
+ if types[0]
155
+ types[0].each { |name, type|
156
+ @vertex_type.register_field(name, VERTEX_FIELDS[type][0])
157
+ @vertex_size += VERTEX_FIELDS[type][1]
158
+ }
159
+ end
160
+ raise "Invalid size for vertex data #{@vertex_size} != #{@header.vertex_size}!" if @vertex_size != @header.vertex_size
161
+ @vertex_ex_type = Class::new(LibBin::Structure)
162
+ @vertex_ex_size = 0
163
+ if types[1]
164
+ types[1].each { |name, type|
165
+ @vertex_ex_type.register_field(name, VERTEX_FIELDS[type][0])
166
+ @vertex_ex_size += VERTEX_FIELDS[type][1]
167
+ }
168
+ end
169
+ raise "Invalid size for ex data #{@vertex_ex_size} != #{@header.vertex_ex_data_size}!" if @vertex_ex_size != @header.vertex_ex_data_size
170
+ return [@vertex_type, @vertex_ex_type]
171
+ end
172
+ end
173
+
174
+ def get_vertex_field(field, vi)
175
+ if @vertexes[vi].respond_to?(field)
176
+ return @vertexes[vi].send(field)
177
+ elsif @vertexes_ex_data && @vertexes_ex_data[vi].respond_to?(field)
178
+ return @vertexes_ex_data[vi].send(field)
179
+ else
180
+ return nil
181
+ end
182
+ end
183
+
184
+ def set_vertex_field(field, vi, val)
185
+ if @vertexes[vi].respond_to?(field)
186
+ return @vertexes[vi].send(:"#{field}=", val)
187
+ elsif @vertexes_ex_data && @vertexes_ex_data[vi].respond_to?(field)
188
+ return @vertexes_ex_data[vi].send(:"#{field}=", val)
189
+ else
190
+ raise "Couldn't find field: #{field}!"
191
+ end
192
+ end
193
+
194
+ class Header < LibBin::Structure
195
+ uint32 :offset_vertexes
196
+ uint32 :offset_vertexes_ex_data
197
+ uint32 :u_a
198
+ uint32 :u_b
199
+ uint32 :vertex_size
200
+ uint32 :vertex_ex_data_size
201
+ uint32 :u_c
202
+ uint32 :u_d
203
+ uint32 :num_vertexes
204
+ uint32 :vertex_flags
205
+ uint32 :offset_indices
206
+ uint32 :num_indices
207
+ end
208
+ register_field :header, Header
209
+ register_field :vertexes, 'get_vertex_types[0]', length: 'header\num_vertexes', offset: 'header\offset_vertexes'
210
+ register_field :vertexes_ex_data, 'get_vertex_types[1]', length: 'header\num_vertexes',
211
+ offset: 'header\offset_vertexes_ex_data'
212
+ register_field :indices, '(..\header.flags & 0x8) != 0 ? UInt32 : UInt16' , length: 'header\num_indices', offset: 'header\offset_indices'
213
+ end
214
+
215
+ class Bone < LibBin::Structure
216
+ int16 :id
217
+ int16 :parent_index
218
+ register_field :local_position, Position
219
+ register_field :local_rotation, Position
220
+ register_field :local_scale, Position
221
+ register_field :position, Position
222
+ register_field :rotation, Position
223
+ register_field :scale, Position
224
+ register_field :t_position, Position
225
+ end
226
+
227
+ class Unknown1 < LibBin::Structure
228
+ uint32 :data, length: 6
229
+ end
230
+
231
+ class InfoPair < LibBin::Structure
232
+ uint32 :offset
233
+ uint32 :number
234
+ end
235
+
236
+ class Header < LibBin::Structure
237
+ def self.info_pair(field, length: nil, count: nil, offset: nil, sequence: false, condition: nil)
238
+ register_field(field, InfoPair, length: length, count: count, offset: offset, sequence: sequence, condition: condition)
239
+ end
240
+
241
+ uint32 :id
242
+ uint32 :version
243
+ int32 :u_a
244
+ int16 :flags
245
+ int16 :u_c
246
+ float :bounding_box, length: 6
247
+ info_pair :info_bones
248
+ info_pair :info_bone_index_translate_table
249
+ info_pair :info_vertex_groups
250
+ info_pair :info_batches
251
+ info_pair :info_lods
252
+ info_pair :info_col_tree_nodes
253
+ info_pair :info_bone_map
254
+ info_pair :info_bone_sets
255
+ info_pair :info_materials
256
+ info_pair :info_meshes
257
+ info_pair :info_mesh_material_pairs
258
+ info_pair :info_unknown1
259
+ end
260
+
261
+ register_field :header, Header
262
+ register_field :bones, Bone, length: 'header\info_bones\number',
263
+ offset: 'header\info_bones\offset'
264
+ register_field :bone_index_translate_table, BoneIndexTranslateTable,
265
+ offset: 'header\info_bone_index_translate_table\offset'
266
+ register_field :vertex_groups, VertexGroup, count: 'header\info_vertex_groups\number',
267
+ sequence: true, offset: 'header\info_vertex_groups\offset + __iterator * 48'
268
+ register_field :batches, Batch, length: 'header\info_batches\number',
269
+ offset: 'header\info_batches\offset'
270
+ register_field :lods, Lod, count: 'header\info_lods\number', sequence: true,
271
+ offset: 'header\info_lods\offset + __iterator * 20'
272
+ register_field :col_tree_nodes, ColTreeNode, length: 'header\info_col_tree_nodes\number',
273
+ offset: 'header\info_col_tree_nodes\offset'
274
+ uint32 :bone_map, length: 'header\info_bone_map\number',
275
+ offset: 'header\info_bone_map\offset'
276
+ register_field :bone_sets, BoneSet, count: 'header\info_bone_sets\number', sequence: true,
277
+ offset: 'header\info_bone_sets\offset + __iterator * 8'
278
+ register_field :materials, Material, count: 'header\info_materials\number', sequence: true,
279
+ offset: 'header\info_materials\offset + __iterator * 48'
280
+ register_field :meshes, Mesh, count: 'header\info_meshes\number', sequence: true,
281
+ offset: 'header\info_meshes\offset + __iterator * 44'
282
+ register_field :mesh_material_pairs, MeshMaterialPair,
283
+ length: 'header\info_mesh_material_pairs\number',
284
+ offset: 'header\info_mesh_material_pairs\offset'
285
+ register_field :unknown1, Unknown1, length: 'header\info_unknown1\number',
286
+ offset: 'header\info_unknown1\offset'
287
+
288
+ def texture_ids
289
+ ids = @materials.collect { |m|
290
+ m.textures.collect { |t| t.texture_id }
291
+ }
292
+ ids.flatten.uniq
293
+ end
294
+
295
+ def materials_textures
296
+ mat_tex = @materials.collect { |m|
297
+ [m.name, m.textures.collect { |t| [t.texture_id, t.name] }]
298
+ }.to_h
299
+ end
300
+
301
+ def cleanup_vertexes
302
+ vertex_usage, index_usage = get_vertex_index_usage
303
+ @vertex_groups.each_with_index { |vertex_group, vertex_group_index|
304
+ new_vertex_map = vertex_usage[vertex_group_index].uniq.sort.each_with_index.to_h
305
+ vertex_group.vertexes = new_vertex_map.keys.collect { |i|
306
+ vertex_group.vertexes[i]
307
+ }
308
+ vertex_group.vertexes_ex_data = new_vertex_map.keys.collect { |i|
309
+ vertex_group.vertexes_ex_data[i]
310
+ }
311
+ vertex_group.header.num_vertexes = vertex_group.vertexes.size
312
+
313
+ new_index_map = index_usage[vertex_group_index].uniq.sort.each_with_index.to_h
314
+ vertex_group.indices = new_index_map.keys.collect { |i|
315
+ new_vertex_map[vertex_group.indices[i]]
316
+ }
317
+ vertex_group.header.num_indices = vertex_group.indices.size
318
+ @batches.select { |batch| batch.vertex_group_index == vertex_group_index }.each { |batch|
319
+ batch.vertex_start = new_vertex_map[batch.vertex_start]
320
+ batch.index_start = new_index_map[batch.index_start]
321
+ if batch.vertex_start != 0
322
+ ((batch.index_start)...(batch.index_start + batch.num_indices)).each { |i|
323
+ vertex_group.indices[i] = vertex_group.indices[i] - batch.vertex_start
324
+ }
325
+ end
326
+ }
327
+ }
328
+ end
329
+
330
+ def get_vertex_index_usage
331
+ vertex_usage = Hash::new { |h, k| h[k] = [] }
332
+ index_usage = Hash::new { |h, k| h[k] = [] }
333
+ @batches.each { |batch|
334
+ index_range = (batch.index_start)...(batch.index_start + batch.num_indices)
335
+ index_usage[batch.vertex_group_index] += index_range.to_a
336
+ vertex_usage[batch.vertex_group_index] += @vertex_groups[batch.vertex_group_index].indices[index_range].collect { |vertex|
337
+ vertex + batch.vertex_start
338
+ }
339
+ }
340
+ return [vertex_usage, index_usage]
341
+ end
342
+
343
+ def delete_meshes(list)
344
+ kept_meshes = @meshes.size.times.to_a - list
345
+ new_mesh_map = kept_meshes.each_with_index.to_h
346
+ if @meshes
347
+ @meshes = kept_meshes.collect { |i|
348
+ @meshes[i]
349
+ }
350
+ @header.info_meshes.number = @meshes.size
351
+ end
352
+ if @mesh_material_pairs
353
+ @mesh_material_pairs = @mesh_material_pairs.select { |pair|
354
+ ! list.include?(pair.mesh_index)
355
+ }
356
+ @header.info_mesh_material_pairs.number = @mesh_material_pairs.size
357
+ @mesh_material_pairs.each { |pair|
358
+ pair.mesh_index = new_mesh_map[pair.mesh_index]
359
+ }
360
+ end
361
+ if @lods && @batches
362
+ batch_indexes = @header.info_batches.number.times.to_a
363
+ filtered_batches = Set::new
364
+ @lods.each { |lod|
365
+ if lod.batch_infos
366
+ lod.batch_infos.each_with_index { |batch_info, index|
367
+ if list.include?(batch_info.mesh_index)
368
+ filtered_batches.add( index + lod.header.batch_start )
369
+ end
370
+ }
371
+ lod.batch_infos = lod.batch_infos.select { |batch_info|
372
+ ! list.include?(batch_info.mesh_index)
373
+ }
374
+ lod.header.num_batch_infos = lod.batch_infos.size
375
+ lod.batch_infos.each { |batch_info|
376
+ batch_info.mesh_index = new_mesh_map[batch_info.mesh_index]
377
+ }
378
+ end
379
+ }
380
+ batch_indexes -= filtered_batches.to_a
381
+ batch_index_map = batch_indexes.each_with_index.to_h
382
+ @batches = batch_indexes.collect { |index|
383
+ @batches[index]
384
+ }
385
+ @header.info_batches.number = @batches.size
386
+ @lods.each { |lod|
387
+ if lod.batch_infos
388
+ lod.header.batch_start = batch_index_map[lod.header.batch_start]
389
+ end
390
+ }
391
+ end
392
+ self
393
+ end
394
+
395
+ def delete_batches(batch_list)
396
+ if @lods && @batches
397
+ batch_indexes = @header.info_batches.number.times.to_a
398
+ batch_indexes -= batch_list
399
+ batch_index_map = batch_indexes.each_with_index.to_h
400
+ @batches = batch_indexes.collect { |index|
401
+ @batches[index]
402
+ }
403
+ @header.info_batches.number = @batches.size
404
+ @lods.each { |lod|
405
+ if lod.batch_infos
406
+ new_batch_infos = []
407
+ lod.batch_infos.each_with_index { |batch_info, index|
408
+ unless batch_list.include?(lod.header.batch_start + index)
409
+ new_batch_infos.push batch_info
410
+ end
411
+ lod.batch_infos = new_batch_infos
412
+ lod.header.num_batch_infos = lod.batch_infos.size
413
+ }
414
+ end
415
+ }
416
+ @lods.each { |lod|
417
+ if lod.batch_infos
418
+ lod.header.batch_start = batch_index_map[lod.header.batch_start]
419
+ end
420
+ }
421
+ end
422
+ end
423
+
424
+ def recompute_layout
425
+ last_offset = 0x88
426
+
427
+ if @header.info_bones.number > 0
428
+ last_offset = @header.info_bones.offset = align(last_offset, 0x10)
429
+ last_offset += @bones.first.__size * @header.info_bones.number
430
+ else
431
+ @header.info_bones.offset = 0x0
432
+ end
433
+
434
+ if @header.info_bones.number > 0
435
+ last_offset = @header.info_bone_index_translate_table.offset = align(last_offset, 0x10)
436
+ last_offset += @bone_index_translate_table.__size
437
+ else
438
+ @header.info_bone_index_translate_table.offset = 0x0
439
+ end
440
+
441
+ if @header.info_vertex_groups.number > 0
442
+ last_offset = @header.info_vertex_groups.offset = align(last_offset, 0x4)
443
+ last_offset += @vertex_groups.first.header.__size * @header.info_vertex_groups.number
444
+ @vertex_groups.each { |vg|
445
+ if vg.header.num_vertexes > 0
446
+ last_offset = vg.header.offset_vertexes = align(last_offset, 0x10)
447
+ last_offset += vg.header.vertex_size * vg.header.num_vertexes
448
+ if vg.header.vertex_ex_data_size > 0
449
+ last_offset = vg.header.offset_vertexes_ex_data = align(last_offset, 0x10)
450
+ last_offset += vg.header.vertex_ex_data_size * vg.header.num_vertexes
451
+ end
452
+ end
453
+ if vg.header.num_indices > 0
454
+ last_offset = vg.header.offset_indices = align(last_offset, 0x10)
455
+ last_offset += (@header.flags & 0x8 > 0 ? 4 : 2) * vg.header.num_indices
456
+ end
457
+ }
458
+ else
459
+ @header.info_vertex_groups.offset = 0x0
460
+ end
461
+
462
+ if @header.info_batches.number > 0
463
+ last_offset = @header.info_batches.offset = align(last_offset, 0x4)
464
+ last_offset += @batches.first.__size * @header.info_batches.number
465
+ else
466
+ @header.info_batches.offset = 0x0
467
+ end
468
+
469
+ if @header.info_lods.number > 0
470
+ last_offset = @header.info_lods.offset = align(last_offset, 0x4)
471
+ last_offset += @lods.first.header.__size * @header.info_lods.number
472
+ @lods.each { |lod|
473
+ if lod.header.num_batch_infos > 0
474
+ lod.header.offset_batch_infos = last_offset
475
+ last_offset += lod.batch_infos.first.__size * lod.header.num_batch_infos
476
+ end
477
+ lod.header.offset_name = last_offset
478
+ last_offset += lod.name.size
479
+ }
480
+ else
481
+ @header.info_lods.offset = 0x0
482
+ end
483
+
484
+ if @header.info_mesh_material_pairs.number > 0
485
+ last_offset = @header.info_mesh_material_pairs.offset = align(last_offset, 0x10)
486
+ last_offset += @mesh_material_pairs.first.__size * @header.info_mesh_material_pairs.number
487
+ else
488
+ @header.info_mesh_material_pairs.offset = 0x0
489
+ end
490
+
491
+ if @header.info_col_tree_nodes.number > 0
492
+ last_offset = @header.info_col_tree_nodes.offset = align(last_offset, 0x10)
493
+ last_offset += @col_tree_nodes.first.__size * @header.info_col_tree_nodes.number
494
+ else
495
+ @header.info_col_tree_nodes.offset = 0x0
496
+ end
497
+
498
+ if @header.info_bone_sets.number > 0
499
+ last_offset = @header.info_bone_sets.offset = align(last_offset, 0x10)
500
+ last_offset += 0x8 * @header.info_bone_sets.number
501
+ @bone_sets.each { |bone_set|
502
+ last_offset = bone_set.offset_bone_indices = align(last_offset, 0x10)
503
+ last_offset += 0x2 * bone_set.num_bone_indices
504
+ }
505
+ else
506
+ @header.info_bone_sets.offset = 0x0
507
+ end
508
+
509
+ if @header.info_bone_map.number > 0
510
+ last_offset = @header.info_bone_map.offset = align(last_offset, 0x10)
511
+ last_offset += 0x4 * @header.info_bone_map.number
512
+ else
513
+ @header.info_bone_map.offset = 0x0
514
+ end
515
+
516
+ if @header.info_meshes.number > 0
517
+ last_offset = @header.info_meshes.offset = align(last_offset, 0x4)
518
+ last_offset += @meshes.first.header.__size * @header.info_meshes.number
519
+ @meshes.each { |mesh|
520
+ mesh.header.offset_name = last_offset
521
+ last_offset += mesh.name.size
522
+ if mesh.header.num_materials > 0
523
+ mesh.header.offset_materials = last_offset
524
+ last_offset += 0x2 * mesh.header.num_materials
525
+ else
526
+ mesh.header.offset_materials = 0x0
527
+ end
528
+ if mesh.header.num_bones_indices > 0
529
+ mesh.header.offset_bones_indices = last_offset
530
+ last_offset += 0x2 * mesh.header.num_bones_indices
531
+ else
532
+ mesh.header.offset_bones_indices = 0x0
533
+ end
534
+ }
535
+ else
536
+ @header.info_meshes.offset = 0x0
537
+ end
538
+
539
+ if @header.info_materials.number > 0
540
+ last_offset = @header.info_materials.offset = align(last_offset, 0x10)
541
+ last_offset += @materials.first.header.__size * @header.info_materials.number
542
+ @materials.each { |material|
543
+ material.header.offset_name = last_offset
544
+ last_offset += material.name.size
545
+ material.header.offset_shader_name = last_offset
546
+ last_offset += material.shader_name.size
547
+ material.header.offset_technique_name = last_offset
548
+ last_offset += material.technique_name.size
549
+ if material.header.num_textures > 0
550
+ material.header.offset_textures = last_offset
551
+ last_offset += 0x8 * material.header.num_textures
552
+ material.textures.each { |texture|
553
+ texture.offset_name = last_offset
554
+ last_offset += texture.name.size
555
+ }
556
+ else
557
+ material.header.offset_textures = 0x0
558
+ end
559
+ if material.header.num_parameters_groups > 0
560
+ last_offset = material.header.offset_parameters_groups = align(last_offset, 0x10)
561
+ last_offset += 0xC * material.header.num_parameters_groups
562
+ material.parameters_groups.each { |parameter_group|
563
+ last_offset = parameter_group.offset_parameters = align(last_offset, 0x10)
564
+ last_offset += 0x4 * parameter_group.num_parameters
565
+ }
566
+ else
567
+ material.header.offset_parameters_group = 0x0
568
+ end
569
+ if material.header.num_variables > 0
570
+ last_offset = material.header.offset_variables = align(last_offset, 0x10)
571
+ last_offset += 0x8 * material.header.num_variables
572
+ material.variables.each { |variable|
573
+ variable.offset_name = last_offset
574
+ last_offset += variable.name.size
575
+ }
576
+ else
577
+ material.header.offset_variables = 0x0
578
+ end
579
+ }
580
+ else
581
+ @header.info_materials.offset = 0x0
582
+ end
583
+
584
+ if @header.info_unknown1.number > 0
585
+ last_offset = @header.info_unknown1.offset = align(last_offset, 0x4)
586
+ last_offset += @unknown1.first.__size * @header.info_unknown1.number
587
+ else
588
+ @header.info_unknown1.offset = 0x0
589
+ end
590
+
591
+ end
592
+
593
+ def was_big?
594
+ @__was_big
595
+ end
596
+
597
+ def get_vertex_field(field, vg, vi)
598
+ @vertex_groups[vg].get_vertex_field(field, vi)
599
+ end
600
+
601
+ def set_vertex_field(field, vg, vi, val)
602
+ @vertex_groups[vg].set_vertex_field(field, vi, val)
603
+ end
604
+
605
+ def scale(s)
606
+ @vertex_groups.each { |vg|
607
+ if vg.vertexes && vg.vertexes.first.respond_to?(:position)
608
+ vg.vertexes.each { |v|
609
+ v.position.x = v.position.x * s
610
+ v.position.y = v.position.y * s
611
+ v.position.z = v.position.z * s
612
+ }
613
+ end
614
+ }
615
+ @bones.each { |b|
616
+ b.position.x = b.position.x * s
617
+ b.position.y = b.position.y * s
618
+ b.position.z = b.position.z * s
619
+ b.local_position.x = b.local_position.x * s
620
+ b.local_position.y = b.local_position.y * s
621
+ b.local_position.z = b.local_position.z * s
622
+ b.t_position.x = b.t_position.x * s
623
+ b.t_position.y = b.t_position.y * s
624
+ b.t_position.z = b.t_position.z * s
625
+ }
626
+ self
627
+ end
628
+
629
+ def dump_bones(list = nil)
630
+ bone_struct = Struct::new(:index, :parent, :relative_position, :position, :global_index, :symmetric, :flag)
631
+ list = (0...@header.num_bones) unless list
632
+ list.collect { |bi|
633
+ bone_struct::new(bi, @bones[bi].parent_index, @bones[bi].local_position, @bones[bi].position,
634
+ @bones[bi].id, -1, 5)
635
+ }
636
+ end
637
+
638
+ def get_vertex_usage
639
+ vertex_usage = Hash::new { |h, k| h[k] = [] }
640
+ @batches.each { |b|
641
+ @vertex_groups[b.vertex_group_index].indices[b.index_start...(b.index_start+b.num_indices)].each { |i|
642
+ vertex_usage[[b.vertex_group_index, i]].push( b )
643
+ }
644
+ }
645
+ vertex_usage.each { |k,v| v.uniq! }
646
+ vertex_usage
647
+ end
648
+
649
+ def recompute_relative_positions
650
+ @bones.each { |b|
651
+ if b.parent_index != -1
652
+ b.local_position = b.position - @bones[b.parent_index].position
653
+ else
654
+ b.local_position = b.position
655
+ end
656
+ }
657
+ self
658
+ end
659
+
660
+ def set_tpose
661
+ neutral_scale = Linalg::Vector::new(1.0, 1.0, 1.0)
662
+ inverse_bind_pose = @bones.collect { |b|
663
+ parent_scale = neutral_scale
664
+ parent_scale = @bones[b.parent_index].scale if b.parent_index != -1
665
+ Linalg::get_inverse_transformation_matrix(b.position, b.rotation, b.scale, parent_scale)
666
+ }
667
+ target_pose = @bones.collect { |b|
668
+ Linalg::get_translation_matrix(b.t_position)
669
+ }
670
+ bones.each { |b|
671
+ b.position = b.t_position
672
+ b.rotation.x = 0.0
673
+ b.rotation.y = 0.0
674
+ b.rotation.z = 0.0
675
+ b.scale.x = 1.0
676
+ b.scale.y = 1.0
677
+ b.scale.z = 1.0
678
+ b.local_rotation.x = 0.0
679
+ b.local_rotation.y = 0.0
680
+ b.local_rotation.z = 0.0
681
+ b.local_scale.x = 1.0
682
+ b.local_scale.y = 1.0
683
+ b.local_scale.z = 1.0
684
+ }
685
+ multiplied_matrices = target_pose.each_with_index.collect { |m, i|
686
+ m * inverse_bind_pose[i]
687
+ }
688
+ vertex_usage = get_vertex_usage
689
+ vertex_usage.each { |(vgi, vi), bs|
690
+ if bs.first.bone_set_index >= 0
691
+ bone_set = bone_sets[bs.first.bone_set_index].bone_indices
692
+ bone_refs = bone_set.collect { |bi| @bone_map[bi] }
693
+ else
694
+ bone_refs = @bone_map
695
+ end
696
+ bone_infos = get_vertex_field(:bone_infos, vgi, vi)
697
+ indexes_and_weights = bone_infos.get_indexes_and_weights
698
+ vertex_matrix = Linalg::get_zero_matrix
699
+ indexes_and_weights.each { |bi, bw|
700
+ i = bone_refs[bi]
701
+ vertex_matrix = vertex_matrix + multiplied_matrices[i] * (bw.to_f/255.to_f)
702
+ }
703
+ vp = get_vertex_field(:position, vgi, vi)
704
+ new_vp = vertex_matrix * Linalg::Vector::new(vp.x, vp.y, vp.z)
705
+ vp.x = new_vp.x
706
+ vp.y = new_vp.y
707
+ vp.z = new_vp.z
708
+ n = get_vertex_field(:normal, vgi, vi)
709
+ new_n = vertex_matrix * Linalg::Vector::new(n.x, n.y, n.z, 0.0)
710
+ n.x = new_n.x
711
+ n.y = new_n.y
712
+ n.z = new_n.z
713
+ t = get_vertex_field(:tangents, vgi, vi)
714
+ new_t = vertex_matrix * Linalg::Vector::new(t.x, t.y, t.z, 0.0)
715
+ t.x = new_t.x
716
+ t.y = new_t.y
717
+ t.z = new_t.z
718
+ }
719
+ self
720
+ end
721
+
722
+ def self.load(input_name)
723
+ if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
724
+ input = input_name
725
+ else
726
+ File.open(input_name, "rb") { |f|
727
+ input = StringIO::new(f.read, "rb")
728
+ }
729
+ end
730
+ wmb = self::new
731
+ wmb.instance_variable_set(:@__was_big, false)
732
+ wmb.__load(input, false)
733
+ input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
734
+ wmb
735
+ end
736
+
737
+ def dump(output_name, output_big = false)
738
+ if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
739
+ output = output_name
740
+ else
741
+ output = StringIO::new("", "wb")#File.open(output_name, "wb")
742
+ end
743
+ output.rewind
744
+
745
+ __set_dump_state(output, output_big, nil, nil)
746
+ __dump_fields
747
+ __unset_dump_state
748
+
749
+
750
+ unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
751
+ File.open(output_name, "wb") { |f|
752
+ f.write output.string
753
+ }
754
+ output.close
755
+ end
756
+ self
757
+ end
758
+ end
759
+ end