pgtools 1.0.0

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