Top Level Namespace

Includes:
Bayonetta

Defined Under Namespace

Modules: Assimp, Bayonetta Classes: BayoMat, WTBFilePartial

Constant Summary

Constants included from Bayonetta

Bayonetta::ANARCHY, Bayonetta::BAYONETTA, Bayonetta::BAYONETTA2, Bayonetta::GAMES, Bayonetta::NIERAUTOMATA, Bayonetta::PC, Bayonetta::PLATFORMS, Bayonetta::PS3, Bayonetta::SUPPORTED, Bayonetta::SWITCH, Bayonetta::VANQUISH, Bayonetta::VERTEX_FIELDS, Bayonetta::WIIU, Bayonetta::XBOX360

Instance Method Summary collapse

Instance Method Details

#add_textures(tex, path, new_tex_list) ⇒ Object



676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 676

def add_textures(tex, path, new_tex_list)
  new_tex_list.each { |tex_path|
    extension = File.extname(tex_path)
    tex_path = convert_windows_path(tex_path) unless $is_win
    old_tex_path = Pathname.new(tex_path).absolute? ? tex_path : File.join(path, tex_path)
    if extension.downcase != ".dds"
      tex_path = Pathname.new(tex_path).absolute? ? File.join(File.dirname(tex_path), File.basename(tex_path,extension)) + ".dds" :
                                      File.join(path, File.join(File.dirname(tex_path), File.basename(tex_path,extension))) + ".dds"
      `convert -define dds:compression=dxt5 #{Shellwords.escape old_tex_path} #{Shellwords.escape tex_path}`
    else
      tex_path = old_tex_path
    end
    tex.push File::new(tex_path, "rb")
  }
end

#apply_mapping(mapping, meshes) ⇒ Object



23
24
25
26
27
28
29
30
31
# File 'lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb', line 23

def apply_mapping(mapping, meshes)
  meshes.each { |m|
    m.batches.each { |b|
      b.bone_refs.collect! { |i|
        mapping[i]
      }
    }
  }
end

#bayo_mat_propertiesObject



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb', line 340

def bayo_mat_properties
  return @mat_properties
  {
    0x31 => BayoMat::new(0x31, 0xC0, 3,  1, -1, -1, -1),
    0x32 => BayoMat::new(0x32, 0xE4, 4,  1, -1, -1,  3),
    0x33 => BayoMat::new(0x33, 0xD4, 4,  2, -1,  1, -1),
    0x34 => BayoMat::new(0x34, 0xF8, 5,  2, -1,  1,  4),
    0x38 => BayoMat::new(0x38, 0xD4, 4, -1,  2, -1, -1),
    0x3A => BayoMat::new(0x3A, 0xD4, 4,  1,  2, -1, -1),
    0x3C => BayoMat::new(0x3C, 0xD4, 4, -1, -1, -1, -1),
    0x40 => BayoMat::new(0x40, 0xC4, 4, -1, -1, -1, -1),
    0x42 => BayoMat::new(0x42, 0xAC, 2, -1, -1, -1, -1),
    0x44 => BayoMat::new(0x44, 0xE4, 4,  1, -1, -1, -1),
    0x47 => BayoMat::new(0x47, 0x68, 1, -1, -1, -1, -1),
    0x48 => BayoMat::new(0x48, 0xC0, 3,  1, -1,  2, -1),
    0x4A => BayoMat::new(0x4A, 0xD4, 4,  2, -1,  1, -1),
    0x4B => BayoMat::new(0x4B, 0xD4, 4, -1,  2, -1, -1),
    0x4C => BayoMat::new(0x4C, 0xAC, 2, -1, -1, -1, -1),
    0x53 => BayoMat::new(0x53, 0x68, 1, -1, -1, -1, -1),
    0x54 => BayoMat::new(0x54, 0xD4, 4,  1, -1, -1, -1),
    0x59 => BayoMat::new(0x59, 0xD4, 4,  1, -1, -1, -1),
    0x60 => BayoMat::new(0x60, 0x68, 1, -1, -1, -1, -1),
    0x68 => BayoMat::new(0x68, 0xAC, 2, -1, -1, -1, -1),
    0x6B => BayoMat::new(0x6B, 0xD0, 3, -1,  1, -1, -1),
    0x6D => BayoMat::new(0x6D, 0xD0, 3, -1,  1, -1, -1),
    0x6E => BayoMat::new(0x6E, 0xD4, 4, -1,  1, -1, -1),
    0x71 => BayoMat::new(0x71, 0xE4, 4,  1, -1, -1, -1),
    0x72 => BayoMat::new(0x72, 0xD4, 4, -1,  1, -1, -1),
    0x75 => BayoMat::new(0x75, 0xAC, 2, -1, -1, -1, -1),
    0x7C => BayoMat::new(0x7C, 0xEA, 4,  1, -1, -1,  3),
    0x7F => BayoMat::new(0x7F, 0x124,4, -1,  1, -1, -1),
    0x81 => BayoMat::new(0x81, 0x120,3, -1, -1, -1, -1),
    0x83 => BayoMat::new(0x83, 0xAC, 2, -1, -1, -1, -1),
    0x87 => BayoMat::new(0x87, 0xD4, 4, -1,  1, -1, -1),
    0x89 => BayoMat::new(0x89, 0xC0, 3,  1, -1, -1,  2),
    0x8F => BayoMat::new(0x8F, 0xD4, 4,  1, -1,  2,  3),
    0x97 => BayoMat::new(0x97, 0x114,4, -1, -1, -1, -1),
    0xA1 => BayoMat::new(0xA1, 0xB0, 3,  1, -1, -1, -1),
    0xA3 => BayoMat::new(0xA3, 0xE4, 4, -1,  1, -1, -1),
    0xB2 => BayoMat::new(0xB2, 0xD4, 4, -1,  1, -1, -1),
    0xB3 => BayoMat::new(0xB3, 0x124,4, -1,  1, -1, -1)
  }
end

#convert_windows_path(path) ⇒ Object



654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 654

def convert_windows_path(path)
  # we are on linux but were given a windows path, hypothesis: linux on windows
  if path.include?("\\")
    res = ""
    copy = path.dup
    if path.start_with?("\\\\")
      res << "//"
      copy = copy[2..-1]
    elsif path.start_with?("\\")
      res << "/"
      copy = copy[2..-1]
    elsif m = path.match(/([A-Za-z]):\\/) #linux on windows
      res << "/mnt/#{m[1].downcase}/"
      copy = copy[3..-1]
    end
    res << copy.gsub("\\", "/")
  else
    res = path
  end
  res
end

#create_bone_hierarchyObject

Meshes



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/bayonetta/tools/wmb_export_assimp.rb', line 87

def create_bone_hierarchy
  skeleton = Assimp::Node::new
  skeleton.name = "skeleton"

  $wmb_bones = bones = $wmb.get_bone_structure
  table = $wmb.bone_index_translate_table.table.invert
  $bone_nodes = bones.collect { |b|
    n = Assimp::Node::new
    n.name = "bone_%03d" % table[b.index]
    n.transformation = Assimp::Matrix4x4.translation(b.relative_position)
    n
  }
  sekeleton_children = []
  bones.zip($bone_nodes).each_with_index { |(b, n), i|
    if b.parent
      n.parent = $bone_nodes[b.parent.index]
    else
      n.parent = skeleton
      sekeleton_children.push(n)
    end
    n.children = b.children.collect { |c| $bone_nodes[c.index] }
  }
  skeleton.children = sekeleton_children
  skeleton
end

#create_mesh(m, i, b, j) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/bayonetta/tools/wmb_export_assimp.rb', line 214

def create_mesh( m, i, b, j)
    uniq_vertices = b.vertex_indices.uniq.sort
    vertex_map = uniq_vertices.each_with_index.collect.to_h
    num_vertices = uniq_vertices.size
    first_index = uniq_vertices.first
    triangles = b.triangles
    num_triangles = triangles.size    

    mesh = Assimp::Mesh::new
    mesh.primitive_types = :TRIANGLE
    mesh.name = ("batch_%02d_" % i) + m.header.name.unpack("Z*").first+("_%02d" % j)
    res = create_vertex_properties(mesh, uniq_vertices, b.bone_refs)
    if $wmb.tex_infos then
      mesh.material_index = b.header.ex_mat_id
    else
      mesh.material_index = b.header.material_id
    end

    mesh.faces = triangles.collect { |tri|
      f = Assimp::Face::new
      t = tri.collect{ |v| vertex_map[v] }
      f.indices = t
      f
    }

    $meshes.push mesh

    n = Assimp::Node::new
    n.name = mesh.name
    n.meshes = [$num_meshes]
    $num_meshes += 1
    n
end

#create_new_meshes(wmb, mesh_mapping) ⇒ Object



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 377

def create_new_meshes(wmb, mesh_mapping)
  new_meshes = mesh_mapping.each_with_index.collect { |(m, _), i|
    new_mesh = WMBFile::Mesh::new
    if $options[:group]
      mesh_name = m
    else
      mesh_name = m.name
    end
    data = mesh_name.match($mesh_prefix)
    if data
      name = mesh_name.gsub(data[0], "")
      mesh_name = name if name != ""
    end
    new_mesh.header.name = mesh_name
    new_mesh.header.id = i + wmb.header.num_meshes
    new_mesh
  }
end

#create_vertex_properties(mesh, vertices, bone_refs) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/bayonetta/tools/wmb_export_assimp.rb', line 113

def create_vertex_properties(mesh, vertices, bone_refs)
  vertex_map = vertices.each_with_index.collect.to_h
  num_vertices = vertices.size
  mesh.num_vertices = num_vertices
  fields = $wmb.get_vertex_fields
  res = {}
  num_colors = 0
  num_texture_coords = 0
  bones = $bone_nodes.each_with_index.collect { |n, i|
      bone = Assimp::Bone::new
      bone.name = n.name
      bone.offset_matrix = Assimp::Matrix4x4.translation( -$wmb_bones[i].position )
      bone
  }
  fields.each { |field|
    case field
    when :position
      mesh.vertices = vertex_map.collect { |orig_index, index|
        p = Assimp::Vector3D::new
        o_p = $wmb.get_vertex_field(field, orig_index)
        p.x = o_p.x
        p.y = o_p.y
        p.z = o_p.z
        p
      }
    when :normal
      mesh.normals = vertex_map.collect { |orig_index, index|
        n = Assimp::Vector3D::new
        o_n = $wmb.get_vertex_field(field, orig_index)
        n.x = o_n.x
        n.y = o_n.y
        n.z = o_n.z
        n
      }
    when :tangents
      mesh.tangents = vertex_map.collect { |orig_index, index|
        t = Assimp::Vector3D::new
        o_t = $wmb.get_vertex_field(field, orig_index)
        t.x = o_t.x
        t.y = o_t.y
        t.z = o_t.z
        t
      }
    when :mapping, :mapping2, :mapping3, :mapping4, :mapping5
      coords = vertex_map.collect { |orig_index, index|
        m = Assimp::Vector3D::new
        m_o = $wmb.get_vertex_field(field, orig_index)
        m.x = m_o.u
        m.y = m_o.v
        m
      }
      mesh.num_uv_components[num_texture_coords] = 2
      mesh.set_texture_coords(num_texture_coords, coords)
      num_texture_coords += 1
    when :color, :color2
      colors = vertex_map.collect { |orig_index, index|
        c = Assimp::Color4D::new
        c_o = $wmb.get_vertex_field(field, orig_index)
        c.r = c_o.r.to_f / 255.0
        c.g = c_o.g.to_f / 255.0
        c.b = c_o.b.to_f / 255.0
        c.a = c_o.a.to_f / 255.0
        c
      }
      mesh.set_colors(num_colors, colors)
      num_colors += 1
    when :bone_infos
      vertex_map.each { |orig_index, index|
        b_i = $wmb.get_vertex_field(field, orig_index).get_indexes_and_weights
        b_i.each { |ind, wgt|
          bone_index = bone_refs[ind]
          bones[bone_index].add_weight(index, wgt/255.0)
        }
      }
    else
      puts "skipping #{field}" unless field == :bone_infos
    end
  }
  bones.select! { |b| b.num_weights > 0 }
#  p bones.collect { |b| b.name }
  mesh.bones = bones
  if mesh.normals? && mesh.tangents?
    tangents = mesh.tangents
    normals = mesh.normals
    mesh.bitangents = vertex_map.collect { |orig_index, index|
      b_t = Assimp::Vector3D::new
      o_t = $wmb.get_vertex_field(:tangents, orig_index)
      t = tangents[index]
      n = normals[index]
      n_b_t = (n ^ t)
      n_b_t = ( o_t.s > 0 ? n_b_t * -1.0 : n_b_t )
      b_t.x = n_b_t.x
      b_t.y = n_b_t.y
      b_t.z = n_b_t.z
      b_t
    }
  end
end

#decode_bone_index_translate_table(wmb, filter = nil) ⇒ Object



26
27
28
29
30
# File 'lib/bayonetta/tools/wmb_get_bone_map.rb', line 26

def decode_bone_index_translate_table(wmb, filter=nil)
  table = wmb.bone_index_translate_table.table.dup
  table.select! { |k,v| filter.include?(k) } if filter
  table
end

#find_bone_mapping(wmb, scene) ⇒ Object



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 228

def find_bone_mapping(wmb, scene)
  tt1 = wmb.bone_index_translate_table.table

  common_mapping = {}

  global_bone_names = tt1.keys
  scene_bones = scene_bones(scene)

  if $options[:auto_map]
    scene_bones.each { |n|
      data = n.name.match($bone_prefix)
      if data
        bone_number = data[1].to_i
        if global_bone_names.include?(bone_number)
          common_mapping[n.name] = bone_number
        end
      end
    }
  elsif $options[:bone_map]
    common_mapping.merge! YAML::load_file( $options[:bone_map] )
  else
    common_mapping = {}
  end

  mapping = {}
  scene_bones.each { |n|
    mapping[n.name] = tt1[common_mapping[n.name]]
  }
  node_mapping = scene_bones.collect { |n| [n.name, n] }.to_h
  [mapping, common_mapping, node_mapping]
end

#find_skeleton(scene) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 151

def find_skeleton(scene)

  known_bones = get_used_bone_set(scene)

  raise "Model uses no bones!" if known_bones.size == 0

  skeleton = nil
  potential_roots = nil

  Assimp::Node.define_method(:eql?) do |other|
      self.class == other.class &&
      self.pointer == other.pointer
  end

  Assimp::Node.define_method(:hash) do
      self.pointer.address.hash
  end

  scene.root_node.each_node { |n|
    if known_bones.include?(n.name)
      potential_roots = n.ancestors unless potential_roots
      potential_roots &= n.ancestors
    end
  }

  Assimp::Node.remove_method :eql?
  Assimp::Node.remove_method :hash

  skeleton = potential_roots.find { |n| n.name.match($skeleton_prefix) }

  if !skeleton
    potential_roots.reverse.each { |n|
      if n.children.find { |c| c.name.match($bone_prefix) }
        skeleton = n
        break
      end
    }
  end

  if !skeleton
    skeleton = potential_roots.first
  end

  skeleton

end

#get_bone_indexes(vertexes) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb', line 33

def get_bone_indexes(vertexes)
  s = Set::new
  vertexes.each { |v|
    bi = v.bone_index
    nbi = 0x0
    ia = 4.times.collect { |i|
      ni = bi & 0xff
      bi >>= 8
      s.add(ni)
    }
  }
  s
end

#get_bone_mapping(source, target) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb', line 8

def get_bone_mapping(source, target)
  mapping = source.each.collect { |p|
    distance = [Float::INFINITY, Float::INFINITY]
    min_index = nil
    target.each { |q|
      d = p.distance(q)
      if ( d[0] <= distance[0] && d[1] < distance[1] ) || d[0] < distance[0]
        distance = d
        min_index = q.index
      end
    }
    [p.index, min_index]
  }.to_h
end

#get_mesh_mapping(scene) ⇒ Object



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 348

def get_mesh_mapping(scene)
  if $options[:group]
    mesh_mapping = Hash::new { |h, k| h[k] = [] }
    scene.meshes.sort { |m1, m2| m1.name <=> m2.name }.each { |m|
      data = m.name.match($batch_prefix)
      if data
        mesh_name = m.name.gsub(data[0], "")
      else
        mesh_name = m.name
      end
      data = mesh_name.match(/_(\d\d)/)
      if data
        mesh_name = mesh_name.gsub(data[0], "")
      end
      mesh_mapping[mesh_name].push(m)
    }
  else
    mesh_nodes = scene.root_node.each_node.select{ |n| n.children.find { |c| c.num_meshes > 0 } }.to_a
    mesh_mapping = mesh_nodes.collect { |n|
      batches = []
      n.children.each { |c|
        batches += c.meshes
      }
      [n, batches.collect{ |num| scene.meshes[num] }]
    }.sort { |(n1, _), (n2, _)| n1.name <=> n2.name }.to_h
  end
  mesh_mapping
end

#get_new_bones(wmb, mapping, node_mapping) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 260

def get_new_bones(wmb, mapping, node_mapping)
  bones_wmb = wmb.get_bone_structure
  if $options[:update_bones]
    common_bones = mapping.reject { |k,v| v.nil? }
    common_bones.each { |k, v|
      p = node_mapping[k].world_transformation * Assimp::Vector3D::new
      pos = bones_wmb[v].position
      pos.x, pos.y, pos.z = p.x, p.y, p.z
    }
  end

  mapping[-1] = -1
  missing_bones = mapping.select { |k,v| v.nil? }.collect { |k,v| k }

  if $options[:filter_bones]
    missing_bones -= $options[:filter_bones]
  end

  new_bone_index = bones_wmb.size
  new_bone_indexes = []

  missing_bones.each { |bi|
    mapping[bi] = new_bone_index
    new_bone_indexes.push(new_bone_index)
    p = node_mapping[bi].world_transformation * Assimp::Vector3D::new
    pos = Position::new
    pos.x, pos.y, pos.z = p.x, p.y, p.z
    b = Bone::new(pos)
    b.index = new_bone_index
    parent_name = nil
    if node_mapping[bi].parent
      parent_name = node_mapping[bi].parent.name
      parent_name = nil unless node_mapping.include?(parent_name)
    end
    b.parent = bones_wmb[mapping[parent_name]] if parent_name
    b.symmetric = -1
    b.flag = 5
    bones_wmb.push b
    new_bone_index += 1
  }
  [bones_wmb, missing_bones, new_bone_indexes]
end

#get_new_tex_list(scene) ⇒ Object



610
611
612
613
614
615
616
617
618
619
620
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 610

def get_new_tex_list(scene)
  texture_set = Set::new
  scene.materials.each { |m|
    m.properties.each { |p|
      if p.key == Assimp::MATKEY_TEXTURE
        texture_set.add p.data
      end
    }
  }
  texture_set.to_a.sort
end

#get_shader_mapObject



384
385
386
387
388
389
390
391
392
393
# File 'lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb', line 384

def get_shader_map
  {
    "ois00_xbceX" => 0xB3,
    "ois01_xbweX" => 0x7f,
    "ois20_xbceX" => 0xB2,
    "skn03_xbXXX" => 0x87,
    "alp03_sbXXX" => 0x42,
    "har01_sbXtX" => 0x84
  }
end

#get_texture_map(tex1, tex2) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/bayonetta/tools/wmb_import_nier.rb', line 89

def get_texture_map(tex1, tex2)
  offset = tex1.each.count
  tex_map = {}
  tex2.each.each_with_index { |t,i|
    info, _ = t
    _, _, idx = info
    idx = i unless idx
    tex_map[idx] = i+offset
  }
  tex_map
end

#get_used_bone_set(scene) ⇒ Object



141
142
143
144
145
146
147
148
149
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 141

def get_used_bone_set(scene)
  known_bones = Set::new
  scene.meshes.each { |m|
    m.bones.each { |b|
      known_bones.add(b.name)
    }
  }
  known_bones
end

#merge_bones(wmb1, wmb2) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/bayonetta/tools/wmb_import_nier.rb', line 8

def merge_bones(wmb1, wmb2)

  tt1 = wmb1.bone_index_translate_table.table
  tt2_orig = wmb2.bone_index_translate_table.table
  tt2 = tt2_orig.invert

  bones1 = wmb1.get_bone_structure
  if $options[:bone_map]
    common_mapping = YAML::load_file( $options[:bone_map] )
  else
    common_mapping = {}
  end

  mapping = {}

  tt2.each { |key, val|
    mapping[key] = tt1[common_mapping[val]]
  }
  mapping = mapping.to_a.sort { |e1, e2| e1.first <=> e2.first }.to_h

  if $options[:update_bones]
    mapping.select { |k,v| v }.each { |k,v|
      bones1[v].position = wmb2.bones[k].position
    }
  end

  mapping[-1] = -1
  missing_bones = mapping.select { |k,v| v.nil? }.collect { |k,v| k }
  if $options[:filter_bones]
    missing_bones -= $options[:filter_bones]
  end
  new_bone_index = bones1.size
  new_bone_indexes = []
  missing_bones.each { |bi|
    mapping[bi] = new_bone_index
    new_bone_indexes.push(new_bone_index)

    b = Bone::new(wmb2.bones[bi].position)
    b.index = new_bone_index
    b.parent = bones1[mapping[wmb2.bones[bi].parent_index]] if wmb2.bones[bi].parent_index != -1
    b.symmetric = -1
    b.flag = 5

    bones1.push b
    new_bone_index += 1
  }
  wmb1.set_bone_structure(bones1)
  missing_bones_count = missing_bones.length
  raise "Too many bones to add!" if missing_bones_count > 0x100
  (align(missing_bones_count, 0x10) - missing_bones_count).times {
    new_bone_indexes.push(0xfff)
  }

  used_indexes = tt1.keys
  start_index = nil

  (0x250..(0x1000-new_bone_indexes.size)).step(0x10) { |s_index|
    if (used_indexes & (s_index..(s_index+new_bone_indexes.size)).to_a) == []
      start_index = s_index
      break
    end
  }
  raise "No room available in translate table!" unless start_index
  new_tt = wmb1.bone_index_translate_table.table.dup
  new_bone_indexes.each_with_index { |ind, i|
    new_tt[i+start_index] = ind
    common_mapping[tt2[missing_bones[i]]] = i + start_index if i < missing_bones.length && missing_bones[i]
  }
  wmb1.bone_index_translate_table.table = new_tt

  if wmb1.bone_symmetries
    (-missing_bones_count..-1).each { |i|
      symmetric = common_mapping[wmb1.bone_symmetries[i]]
      symmetric = -1 unless symmetric
      wmb1.bone_symmetries[i] = symmetric
    }
  end

  [common_mapping, mapping]
end

#merge_geometry(wmb, scene, bone_mapping) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/bayonetta/tools/wmb_import_nier.rb', line 101

def merge_geometry(wmb1, wmb2, bone_mapping)
  new_meshes = wmb2.header.info_meshes.number.times.collect { WMBFile::Mesh::new }
  new_meshes.each_with_index { |m, i|
    m.header.name = wmb2.meshes[i].name
    m.header.id = i + wmb1.header.num_meshes
  }

  batch_infos_map = {}
  wmb2.lods.each { |l|
    l.batch_infos.each_with_index { |batch_info, i|
      batch_infos_map[i+l.header.batch_start] = batch_info
    }
  }

  vertex_types = wmb1.get_vertex_types

  wmb2.batches.each_with_index { |n_b, batch_index|
    v_g = wmb2.vertex_groups[n_b.vertex_group_index]
    b_s = wmb2.bone_sets[n_b.bone_set_index]
    b = WMBFile::Batch::new
    first_vertex_index = wmb1.vertexes.length
    indices = v_g.indices.slice(n_b.index_start, n_b.num_indices)
    index_set = indices.uniq.sort
    num_vertex = index_set.length
    index_map = index_set.each_with_index.collect { |ind, i|
      [ind, i+first_vertex_index]
    }


    wmb1.vertexes += num_vertex.times.collect {
      vertex_types[0]::new
    }
    if wmb1.vertexes_ex_data
      wmb1.vertexes_ex_data += num_vertex.times.collect {
        vertex_types[1]::new
      }
    end
    wmb1.header.num_vertexes += num_vertex

    fields = wmb1.get_vertex_fields
    fields.each { |field|
      unless v_g.get_vertex_field(field, 0)
        warn "Couldn't find vertex field #{field} in model 2"
        if field == :color
          warn "Using default value 0xc0 0xc0 0xc0 0xff"
          c = Color::new
          c.r = 0xc0
          c.g = 0xc0
          c.b = 0xc0
          c.a = 0xff
          index_map.each { |ind, i|
            wmb1.set_vertex_field(field, i, c)
          }
        elsif field == :mapping2
          warn "Using mapping as default"
          index_map.each { |ind, i|
            wmb1.set_vertex_field(field, i, v_g.get_vertex_field(:mapping, ind))
          }
        else
          warn "No suitable default found"
        end
      else
        if field == :normal
          index_map.each { |ind, i|
            n = Normal::new
            n2 = v_g.get_vertex_field(:normal, ind)
            n.x = n2.x
            n.y = n2.y
            n.z = n2.z
            wmb1.set_vertex_field(field, i, n)
          }
        else
          index_map.each { |ind, i|
            wmb1.set_vertex_field(field, i, v_g.get_vertex_field(field, ind))
          }
        end
      end
    }

    index_map = index_map.to_h

    batch_info = batch_infos_map[batch_index]
    mesh = new_meshes[batch_info.mesh_index]

    b.header.material_id = batch_info.material_index + wmb1.header.num_materials
    b.header.mesh_id = mesh.header.id
    b.header.num_indices = indices.length
    b.indices = indices.collect { |ind| index_map[ind] }
    b.recompute_from_absolute_indices
    b.bone_refs = b_s.bone_indices.collect { |bi| bone_mapping[wmb2.bone_map[bi]] }
    b.num_bone_ref = b.bone_refs.length

    mesh.batches.push b
    mesh.header.num_batch += 1
  }

  wmb1.meshes += new_meshes
  wmb1.header.num_meshes += new_meshes.length

end

#merge_materials(wmb1, wmb2, tex_map) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/bayonetta/tools/wmb_import_nier.rb', line 202

def merge_materials(wmb1, wmb2, tex_map)
  new_mat_offset = wmb1.header.num_materials
  mat_offset = wmb1.materials_offsets.last + wmb1.materials.last.__size
  new_materials_offsets = []
  new_materials = []

  wmb2.materials.each_with_index { |e, i|
    #biggest known material( in fact biggset is 0x174)
    new_materials_offsets.push(mat_offset + i*0x124)
    m = WMBFile::Material::new
    m.type = 0x0
    m.flag = 0x0
    m.material_data = [0x0]*(0x120/4)
    albedo = e.textures.find { |t| t.name.match("g_AlbedoMap") }
    normal = e.textures.find { |t| t.name.match("g_NormalMap") }
    m.material_data[0] = (albedo ? tex_map[albedo.texture_id] : 0x80000000)
    m.material_data[1] = (normal ? tex_map[normal.texture_id] : 0x80000000)
    m.material_data[0] = (m.material_data[0] ? m.material_data[0] : 0x80000000)
    m.material_data[1] = (m.material_data[1] ? m.material_data[1] : 0x80000000)
    new_materials.push(m)
  }

  wmb1.header.num_materials += wmb2.header.info_materials.number
  wmb1.materials += new_materials
  wmb1.materials_offsets += new_materials_offsets
end

#merge_meshes(wmb1, wmb2) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb', line 204

def merge_meshes(wmb1, wmb2)
  new_vertex_offset = wmb1.header.num_vertexes - wmb2.header.num_vertexes
  mesh_offset = align(wmb1.meshes_offsets.last + wmb1.meshes.last.__size, 0x20)
  new_meshes_offset = wmb2.meshes_offsets.collect { |e|
    e + mesh_offset
  }
  wmb2.meshes.each_with_index { |m, i|
    m.header.id = i + wmb1.header.num_meshes
    m.batches.each { |b|
      b.header.mesh_id = m.header.id
      if !wmb1.is_bayo2? && wmb2.is_bayo2?
        b.header.batch_id = 0x0
        b.header.flags = 0x8001
        if b.header.u_e1 == 0x10
          b.header.u_e1 = 0x0
        elsif b.header.u_e1 == 0x30
          b.header.u_e1 = 0x20
          b.header.u_e2 = 0x0f
        end
      end
      b.header.vertex_start += new_vertex_offset
      b.header.vertex_end += new_vertex_offset
      b.header.vertex_offset += new_vertex_offset
    }
  }

  wmb1.header.num_meshes += wmb2.header.num_meshes
  wmb1.meshes +=  wmb2.meshes
  wmb1.meshes_offsets += new_meshes_offset
end

#merge_vertexes(wmb1, wmb2) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/bayonetta/tools/wmb_import_geometry_wiiu_pc.rb', line 156

def merge_vertexes(wmb1, wmb2)
  num_vertex1 = wmb1.header.num_vertexes
  num_vertex2 = wmb2.header.num_vertexes

  vertex_types = wmb1.get_vertex_types

  wmb1.vertexes += num_vertex2.times.collect {
    vertex_types[0]::new
  }

  if wmb1.vertexes_ex_data
    wmb1.vertexes_ex_data += num_vertex2.times.collect {
      vertex_types[1]::new
    }
  end

  wmb1.header.num_vertexes += num_vertex2

  wmb1.get_vertex_fields.each { |field|
    unless wmb2.get_vertex_field(field, 0)
      warn "Couldn't find vertex field #{field} in model 2"
      if field == :color
        warn "Using default value 0xc0 0xc0 0xc0 0xff"
        c = Color::new
        c.r = 0xc0
        c.g = 0xc0
        c.b = 0xc0
        c.a = 0xff
        num_vertex2.times { |i|
          wmb1.set_vertex_field(field, num_vertex1 + i, c)
        }
      elsif field == :mapping2
        warn "Using mapping as default"
        num_vertex2.times { |i|
          wmb1.set_vertex_field(field, num_vertex1 + i, wmb2.get_vertex_field(:mapping, i))
        }
      else
        warn "No suitable default found..."
      end
    else
      num_vertex2.times { |i|
        wmb1.set_vertex_field(field, num_vertex1 + i, wmb2.get_vertex_field(field, i))
      }
    end
  }
  return num_vertex1
end

#scene_bones(scene) ⇒ Object



213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 213

def scene_bones(scene)
   skeleton = find_skeleton(scene)
   bones = []
   skeleton.children.each { |c|
     bones += c.each_node_with_depth.collect.to_a
   }
#this doesn't always work
   bones.sort! { |(n1, d1), (n2, d2)|
     n1.name <=> n2.name
   } if $options[:sort]
   bones.collect! { |n, d| n }
   bones = [skeleton] + bones if $options[:root]
   bones
end

#set_fields(wmb, bone_mapping, batch, new_indices, transform_matrix) ⇒ Object



396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 396

def set_fields(wmb, bone_mapping, batch, new_indices, transform_matrix)
  recompute_tangents = false
  bone_refs = {}
  bone_refs = batch.bones.sort { |b1, b2|
      b1.name <=> b2.name
    }.collect(&:name).uniq.each_with_index.collect { |b, i|
      [b, i]
    }.to_h
  fields = wmb.get_vertex_fields

  _, rotation, _ = transform_matrix.decompose

  fields.each do |field|
  case field
  when :position
    vertices = batch.vertices
    new_indices.each_with_index { |target_index, index|
      p = Position::new
      o_p = vertices[index]
      o_p = transform_matrix * o_p
      p.x = o_p.x
      p.y = o_p.y
      p.z = o_p.z
      wmb.set_vertex_field(field, target_index, p)
    }
  when :normal
    normals = batch.normals
    new_indices.each_with_index { |target_index, index|
      n = Normal::new
      o_n = normals[index]
      o_n = rotation * o_n
      n.x = o_n.x
      n.y = o_n.y
      n.z = o_n.z
      wmb.set_vertex_field(field, target_index, n)
    }
  when :tangents
    tangents = batch.tangents
    bitangents = batch.bitangents
    normals = batch.normals
    new_indices.each_with_index { |target_index, index|
      t = Tangents::new
      o_t = tangents[index]
      if o_t
        o_t = rotation * o_t
        o_n = normals[index]
        o_n = rotation * o_n
        o_b = bitangents[index]
        o_b = rotation * o_b
        n_o_b = (o_n ^ o_t)
        if (n_o_b + o_b).length > 1
          s = -1.0
        else
          s = 1.0
        end
        if o_t.x.nan? || o_t.y.nan? || o_t.z.nan?
          t.set(0, 0, 0, 1)
        else
          t.set(o_t.x, o_t.y, o_t.z, s)
        end
      else
        warn "Invalid mapping for batch: #{batch.name}, tangents will be recomputed!" unless recompute_tangents
        recompute_tangents = true
        t.set(0, 0, 0, 1)
      end
      wmb.set_vertex_field(field, target_index, t)
    }
  when :mapping, :mapping2, :mapping3, :mapping4, :mapping5
    mapping_index = 0
    mapping_index = 1 if field == :mapping2
    mapping_index = 2 if field == :mapping3
    mapping_index = 3 if field == :mapping4
    mapping_index = 4 if field == :mapping5
    mapping_index = 0 if batch.num_uv_components[mapping_index] < 2
    texture_coords = batch.texture_coords[mapping_index]
    raise "No texture coordinate found!" unless texture_coords
    new_indices.each_with_index { |target_index, index|
      m = Mapping::new
      o_m = texture_coords[index]
      m.u = o_m.x
      m.v = o_m.y
      wmb.set_vertex_field(field, target_index, m)
    }
  when :color, :color2
    color_index = 0
    color_index = 1 if field == :color2
    colors = batch.colors[color_index]
    if colors
      new_indices.each_with_index { |target_index, index|
        c = Color::new
        o_c = colors[index]
        c.r = (o_c.r * 255.0).round.clamp(0, 255)
        c.g = (o_c.g * 255.0).round.clamp(0, 255)
        c.b = (o_c.b * 255.0).round.clamp(0, 255)
        c.a = (o_c.a < 0 ? 255 : (c.a * 255.0).round.clamp(0, 255))
        wmb.set_vertex_field(field, target_index, c)
      }
    else
      c = Color::new
      c.r = 0xc0
      c.g = 0xc0
      c.b = 0xc0
      c.a = 0xff
      new_indices.each_with_index { |target_index, _|
        wmb.set_vertex_field(field, target_index, c)
      }
    end
  when :bone_infos
    bone_infos = new_indices.size.times.collect {
      []
    }
    batch.bones.each { |bone|
      bone_index = bone_refs[bone.name]
      raise "Missing bone: #{bone.name}!" unless bone_index
      bone.weights.each { |vtxweight|
        vertex_id = vtxweight.vertex_id
        weight = vtxweight.weight
        bone_infos[vertex_id].push [bone_index, weight]
      }
    }
    bone_infos = bone_infos.collect { |bone_info|
      b_i = bone_info.sort { |(_, w1), (_, w2)| w1 <=> w2 }.reverse.first(4).reject { |_, w| w <= 0.0 }
      if b_i.length == 0
        warn "Invalid rigging for batch: #{batch.name}, orphan vertex!"
      else
        sum = b_i.reduce(0.0) { |memo, (_, w)| memo + w }
        b_i.collect! { |ind, w| [ind, (w*255.0/sum).round.clamp(0, 255)] }
        sum = b_i.reduce(0) { |memo, (_, w)| memo + w }
        if sum != 255
          diff = 255 - sum
          b_i.first[1] += diff
        end
      end
      b_i
    }
    
    new_indices.each_with_index { |target_index, index|
      bi = BoneInfos::new
      bi.set_indexes_and_weights(bone_infos[index])
      wmb.set_vertex_field(field, target_index, bi)
    }
  else
    raise "Unknow field in wmb file #{field.inspect}!"
  end
  end
  [bone_refs, recompute_tangents]
end

#update_translate_table(wmb, common_mapping, missing_bones, new_bone_indexes) ⇒ Object



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/bayonetta/tools/wmb_import_assimp.rb', line 303

def update_translate_table(wmb, common_mapping, missing_bones, new_bone_indexes)
  missing_bones_count = new_bone_indexes.length
  raise "Too many bones to add: #{missing_bones.inspect}!" if missing_bones_count > 0x100
  (align(missing_bones_count, 0x10) - missing_bones_count).times {
    new_bone_indexes.push(0xfff)
  }

  tt = wmb.bone_index_translate_table.table
  used_indexes = tt.keys
  start_index = nil

  (0x250..(0x1000-new_bone_indexes.size)).step(0x10) { |s_index|
    if (used_indexes & (s_index..(s_index+new_bone_indexes.size)).to_a) == []
      start_index = s_index
      break
    end
  }
  raise "No room available in translate table!" unless start_index
  new_tt = wmb.bone_index_translate_table.table.dup
  new_bone_indexes.each_with_index { |ind, i|
    new_tt[i+start_index] = ind
    common_mapping[missing_bones[i]] = i + start_index if i < missing_bones.length && missing_bones[i]
  }
  wmb.bone_index_translate_table.table = new_tt
  if wmb.bone_symmetries
    (-missing_bones_count..-1).each { |i|
      symmetric = common_mapping[wmb.bone_symmetries[i]]
      symmetric = -1 unless symmetric
      wmb.bone_symmetries[i] = symmetric
    }
  end
end

#which(cmd) ⇒ Object



7
8
9
10
11
12
13
# File 'lib/bayonetta/tools/wtb_convert_wiiu_pc.rb', line 7

def which(cmd)
  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
    exe = File.join(path, cmd)
    return exe if File.executable?(exe) && !File.directory?(exe)
  end
  nil
end