mirror of https://github.com/AxioDL/metaforce.git
98 lines
3.1 KiB
Python
98 lines
3.1 KiB
Python
'''
|
|
HMDL Export Blender Addon
|
|
By Jack Andersen <jackoalan@gmail.com>
|
|
|
|
This file defines the `hmdl_skin` class to iteratively construct
|
|
a Skinning Info Section for HMDL files. Used by draw-format
|
|
generators to select an optimal skin entry for a draw primitive,
|
|
or have a new one established.
|
|
'''
|
|
|
|
import struct
|
|
import bpy
|
|
|
|
class hmdl_skin:
|
|
|
|
# Set up with HMDL containing ARMATURE `object`
|
|
def __init__(self, max_bone_count, vertex_groups):
|
|
self.max_bone_count = max_bone_count
|
|
self.mesh_vertex_groups = vertex_groups
|
|
|
|
self.bone_arrays = []
|
|
|
|
|
|
# Augment bone array with loop vert and return weight array
|
|
# Returns 'None' if bone overflow
|
|
def augment_bone_array_with_lv(self, mesh_data, bone_array, loop_vert):
|
|
vertex = mesh_data.vertices[loop_vert[0].loop.vertex_index]
|
|
|
|
# Loop-vert weight array
|
|
weight_array = []
|
|
for i in range(len(bone_array)):
|
|
weight_array.append(0.0)
|
|
|
|
# Tentative bone additions
|
|
new_bones = []
|
|
|
|
|
|
# Determine which bones (vertex groups) belong to loop_vert
|
|
for group_elem in vertex.groups:
|
|
vertex_group = self.mesh_vertex_groups[group_elem.group]
|
|
|
|
if vertex_group.name not in bone_array:
|
|
|
|
# Detect bone overflow
|
|
if len(bone_array) + len(new_bones) >= self.max_bone_count:
|
|
return None
|
|
|
|
# Add to array otherwise
|
|
new_bones.append(vertex_group.name)
|
|
|
|
# Record bone weight
|
|
weight_array.append(group_elem.weight)
|
|
|
|
else:
|
|
|
|
# Record bone weight
|
|
weight_array[bone_array.index(vertex_group.name)] = group_elem.weight
|
|
|
|
|
|
# If we get here, no overflows; augment bone array and return weight array
|
|
bone_array.extend(new_bones)
|
|
return weight_array
|
|
|
|
|
|
# Augment triangle-strip bone array to rigging info
|
|
def augment_skin(self, bone_array):
|
|
if bone_array not in self.bone_arrays:
|
|
self.bone_arrays.append(bone_array)
|
|
return (len(self.bone_arrays)-1)
|
|
return self.bone_arrays.index(bone_array)
|
|
|
|
|
|
# Generate Rigging Info structure (call after all index-buffers generated)
|
|
def generate_rigging_info(self, bone_dict, endian_char):
|
|
|
|
skin_entries = []
|
|
for bone_array in self.bone_arrays:
|
|
skin_bytes = bytearray()
|
|
skin_bytes += struct.pack(endian_char + 'I', len(bone_array))
|
|
for bone in bone_array:
|
|
skin_bytes += struct.pack(endian_char + 'I', bone_dict[bone])
|
|
skin_entries.append(skin_bytes)
|
|
|
|
# Generate skinning data
|
|
info_bytes = bytearray()
|
|
info_bytes += struct.pack(endian_char + 'I', len(skin_entries))
|
|
|
|
cur_offset = len(skin_entries) * 4 + 4
|
|
for entry in skin_entries:
|
|
info_bytes += struct.pack(endian_char + 'I', cur_offset)
|
|
cur_offset += len(entry)
|
|
|
|
for entry in skin_entries:
|
|
info_bytes += entry
|
|
|
|
return info_bytes
|
|
|