* Fixed a bug where animations could fail to import if the order of the PSA bones did not match the DFS-order of the target armature.
* Added Select All + Deselect All to PSA export operator
This commit is contained in:
@@ -43,17 +43,19 @@ from bpy.props import PointerProperty
|
|||||||
classes = [
|
classes = [
|
||||||
psk_exporter.PskExportOperator,
|
psk_exporter.PskExportOperator,
|
||||||
psk_importer.PskImportOperator,
|
psk_importer.PskImportOperator,
|
||||||
psa_exporter.PsaExportOperator,
|
|
||||||
psa_importer.PsaImportOperator,
|
psa_importer.PsaImportOperator,
|
||||||
psa_importer.PsaImportFileSelectOperator,
|
psa_importer.PsaImportFileSelectOperator,
|
||||||
psa_importer.PSA_UL_ActionList,
|
psa_importer.PSA_UL_ActionList,
|
||||||
psa_importer.PSA_UL_ImportActionList,
|
psa_importer.PSA_UL_ImportActionList,
|
||||||
psa_exporter.PsaExportActionListItem,
|
|
||||||
psa_importer.PsaImportActionListItem,
|
psa_importer.PsaImportActionListItem,
|
||||||
psa_importer.PsaImportSelectAll,
|
psa_importer.PsaImportSelectAll,
|
||||||
psa_importer.PsaImportDeselectAll,
|
psa_importer.PsaImportDeselectAll,
|
||||||
psa_importer.PSA_PT_ImportPanel,
|
psa_importer.PSA_PT_ImportPanel,
|
||||||
psa_importer.PsaImportPropertyGroup,
|
psa_importer.PsaImportPropertyGroup,
|
||||||
|
psa_exporter.PsaExportOperator,
|
||||||
|
psa_exporter.PsaExportSelectAll,
|
||||||
|
psa_exporter.PsaExportDeselectAll,
|
||||||
|
psa_exporter.PsaExportActionListItem,
|
||||||
psa_exporter.PsaExportPropertyGroup,
|
psa_exporter.PsaExportPropertyGroup,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
box.label(text='Actions', icon='ACTION')
|
box.label(text='Actions', icon='ACTION')
|
||||||
row = box.row()
|
row = box.row()
|
||||||
row.template_list('PSA_UL_ActionList', 'asd', scene.psa_export, 'action_list', scene.psa_export, 'action_list_index', rows=10)
|
row.template_list('PSA_UL_ActionList', 'asd', scene.psa_export, 'action_list', scene.psa_export, 'action_list_index', rows=10)
|
||||||
|
row = box.row()
|
||||||
|
row.operator('psa_export.actions_select_all', text='Select All')
|
||||||
|
row.operator('psa_export.actions_deselect_all', text='Deselect All')
|
||||||
|
|
||||||
def is_action_for_armature(self, action):
|
def is_action_for_armature(self, action):
|
||||||
if len(action.fcurves) == 0:
|
if len(action.fcurves) == 0:
|
||||||
@@ -120,3 +123,23 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
exporter = PsaExporter(psa)
|
exporter = PsaExporter(psa)
|
||||||
exporter.export(self.filepath)
|
exporter.export(self.filepath)
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class PsaExportSelectAll(bpy.types.Operator):
|
||||||
|
bl_idname = 'psa_export.actions_select_all'
|
||||||
|
bl_label = 'Select All'
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
for action in context.scene.psa_export.action_list:
|
||||||
|
action.is_selected = True
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class PsaExportDeselectAll(bpy.types.Operator):
|
||||||
|
bl_idname = 'psa_export.actions_deselect_all'
|
||||||
|
bl_label = 'Deselect All'
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
for action in context.scene.psa_export.action_list:
|
||||||
|
action.is_selected = False
|
||||||
|
return {'FINISHED'}
|
||||||
|
|||||||
@@ -61,28 +61,26 @@ class PsaImporter(object):
|
|||||||
# Create intermediate bone data for import operations.
|
# Create intermediate bone data for import operations.
|
||||||
import_bones = []
|
import_bones = []
|
||||||
import_bones_dict = dict()
|
import_bones_dict = dict()
|
||||||
|
|
||||||
for psa_bone_index, psa_bone in enumerate(psa.bones):
|
for psa_bone_index, psa_bone in enumerate(psa.bones):
|
||||||
bone_name = psa_bone.name.decode('windows-1252')
|
bone_name = psa_bone.name.decode('windows-1252')
|
||||||
print(bone_name)
|
|
||||||
if psa_bone_index not in psa_to_armature_bone_indices: # TODO: replace with bone_name in armature_data.bones
|
if psa_bone_index not in psa_to_armature_bone_indices: # TODO: replace with bone_name in armature_data.bones
|
||||||
# PSA bone does not map to armature bone, skip it and leave an empty bone in its place.
|
# PSA bone does not map to armature bone, skip it and leave an empty bone in its place.
|
||||||
import_bones.append(None)
|
import_bones.append(None)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
import_bone = ImportBone(psa_bone)
|
import_bone = ImportBone(psa_bone)
|
||||||
armature_bone = armature_data.bones[bone_name]
|
import_bone.armature_bone = armature_data.bones[bone_name]
|
||||||
import_bone.pose_bone = armature_object.pose.bones[bone_name]
|
import_bone.pose_bone = armature_object.pose.bones[bone_name]
|
||||||
|
import_bones_dict[bone_name] = import_bone
|
||||||
|
import_bones.append(import_bone)
|
||||||
|
|
||||||
if armature_bone.parent is not None:
|
for import_bone in filter(lambda x: x is not None, import_bones):
|
||||||
if armature_bone.parent.name in psa_bone_names:
|
armature_bone = import_bone.armature_bone
|
||||||
|
if armature_bone.parent is not None and armature_bone.parent.name in psa_bone_names:
|
||||||
import_bone.parent = import_bones_dict[armature_bone.parent.name]
|
import_bone.parent = import_bones_dict[armature_bone.parent.name]
|
||||||
else:
|
# Calculate the original location & rotation of each bone (in world-space maybe?)
|
||||||
import_bone.parent = None
|
|
||||||
|
|
||||||
# Calculate the original location & rotation of each bone (in world space maybe?)
|
|
||||||
# TODO: check if the armature bones have custom data written to them and use that instead.
|
|
||||||
if armature_bone.get('orig_quat') is not None:
|
if armature_bone.get('orig_quat') is not None:
|
||||||
# TODO: ideally we don't rely on bone auxiliary data like this, the non-aux data path is incorrect (animations are flipped 180)
|
# TODO: ideally we don't rely on bone auxiliary data like this, the non-aux data path is incorrect (animations are flipped 180 around Z)
|
||||||
import_bone.orig_quat = Quaternion(armature_bone['orig_quat'])
|
import_bone.orig_quat = Quaternion(armature_bone['orig_quat'])
|
||||||
import_bone.orig_loc = Vector(armature_bone['orig_loc'])
|
import_bone.orig_loc = Vector(armature_bone['orig_loc'])
|
||||||
import_bone.post_quat = Quaternion(armature_bone['post_quat'])
|
import_bone.post_quat = Quaternion(armature_bone['post_quat'])
|
||||||
@@ -97,16 +95,13 @@ class PsaImporter(object):
|
|||||||
import_bone.orig_loc = armature_bone.matrix_local.translation.copy()
|
import_bone.orig_loc = armature_bone.matrix_local.translation.copy()
|
||||||
import_bone.orig_quat = armature_bone.matrix_local.to_quaternion()
|
import_bone.orig_quat = armature_bone.matrix_local.to_quaternion()
|
||||||
import_bone.post_quat = import_bone.orig_quat.conjugated()
|
import_bone.post_quat = import_bone.orig_quat.conjugated()
|
||||||
import_bones_dict[bone_name] = import_bone
|
|
||||||
import_bones.append(import_bone)
|
|
||||||
|
|
||||||
# Create and populate the data for new sequences.
|
# Create and populate the data for new sequences.
|
||||||
for sequence in sequences:
|
for sequence in sequences:
|
||||||
action = bpy.data.actions.new(name=sequence.name.decode())
|
action = bpy.data.actions.new(name=sequence.name.decode())
|
||||||
# TODO: problem might be here (yea, we are confused about the ordering of these things!)
|
|
||||||
for psa_bone_index, armature_bone_index in psa_to_armature_bone_indices.items():
|
for psa_bone_index, armature_bone_index in psa_to_armature_bone_indices.items():
|
||||||
import_bone = import_bones[psa_bone_index]
|
import_bone = import_bones[psa_bone_index]
|
||||||
pose_bone = armature_object.pose.bones[armature_bone_index]
|
pose_bone = import_bone.pose_bone
|
||||||
|
|
||||||
# rotation
|
# rotation
|
||||||
rotation_data_path = pose_bone.path_from_id('rotation_quaternion')
|
rotation_data_path = pose_bone.path_from_id('rotation_quaternion')
|
||||||
|
|||||||
Reference in New Issue
Block a user