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,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