mirror of
https://github.com/DarklightGames/io_scene_psk_psa.git
synced 2025-02-08 06:48:19 +01:00
Added the ability to prefix and suffix sequence names on PSA export
This commit is contained in:
parent
e52aa8975a
commit
04503ed282
@ -12,6 +12,8 @@ class PsaBuilderOptions(object):
|
|||||||
self.bone_group_indices = []
|
self.bone_group_indices = []
|
||||||
self.should_use_original_sequence_names = False
|
self.should_use_original_sequence_names = False
|
||||||
self.should_trim_timeline_marker_sequences = True
|
self.should_trim_timeline_marker_sequences = True
|
||||||
|
self.sequence_name_prefix = ''
|
||||||
|
self.sequence_name_suffix = ''
|
||||||
|
|
||||||
|
|
||||||
class PsaBuilder(object):
|
class PsaBuilder(object):
|
||||||
@ -129,10 +131,14 @@ class PsaBuilder(object):
|
|||||||
else:
|
else:
|
||||||
raise ValueError(f'Unhandled sequence source: {options.sequence_source}')
|
raise ValueError(f'Unhandled sequence source: {options.sequence_source}')
|
||||||
|
|
||||||
frame_start_index = 0
|
# Add prefixes and suffices to the names of the export sequences and strip whitespace.
|
||||||
|
for export_sequence in export_sequences:
|
||||||
|
export_sequence.name = f'{options.sequence_name_prefix}{export_sequence.name}{options.sequence_name_suffix}'.strip()
|
||||||
|
|
||||||
# Now build the PSA sequences.
|
# Now build the PSA sequences.
|
||||||
# We actually alter the timeline frame and simply record the resultant pose bone matrices.
|
# We actually alter the timeline frame and simply record the resultant pose bone matrices.
|
||||||
|
frame_start_index = 0
|
||||||
|
|
||||||
for export_sequence in export_sequences:
|
for export_sequence in export_sequences:
|
||||||
armature.animation_data.action = export_sequence.action
|
armature.animation_data.action = export_sequence.action
|
||||||
context.view_layer.update()
|
context.view_layer.update()
|
||||||
|
@ -91,6 +91,9 @@ class PsaExportPropertyGroup(PropertyGroup):
|
|||||||
bone_group_list: CollectionProperty(type=BoneGroupListItem)
|
bone_group_list: CollectionProperty(type=BoneGroupListItem)
|
||||||
bone_group_list_index: IntProperty(default=0, name='', description='')
|
bone_group_list_index: IntProperty(default=0, name='', description='')
|
||||||
should_use_original_sequence_names: BoolProperty(default=False, name='Original Names', description='If the action was imported from the PSA Import panel, the original name of the sequence will be used instead of the Blender action name', update=should_use_original_sequence_names_updated)
|
should_use_original_sequence_names: BoolProperty(default=False, name='Original Names', description='If the action was imported from the PSA Import panel, the original name of the sequence will be used instead of the Blender action name', update=should_use_original_sequence_names_updated)
|
||||||
|
should_trim_timeline_marker_sequences: BoolProperty(default=True, name='Trim Sequences', description='Frames without NLA track information at the boundaries of timeline markers will be excluded from the exported sequences')
|
||||||
|
sequence_name_prefix: StringProperty(name='Prefix')
|
||||||
|
sequence_name_suffix: StringProperty(name='Suffix')
|
||||||
|
|
||||||
|
|
||||||
def is_bone_filter_mode_item_available(context, identifier):
|
def is_bone_filter_mode_item_available(context, identifier):
|
||||||
@ -122,29 +125,36 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
pg = context.scene.psa_export
|
pg = context.scene.psa_export
|
||||||
|
|
||||||
# SOURCE
|
# SOURCE
|
||||||
layout.prop(pg, 'sequence_source', text='Source')
|
layout.prop(pg, 'sequence_source', text='Source', icon='ACTION' if pg.sequence_source == 'ACTIONS' else 'MARKER')
|
||||||
|
|
||||||
|
# SELECT ALL/NONE
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.label(text='Select')
|
||||||
|
row.operator(PsaExportActionsSelectAll.bl_idname, text='All', icon='CHECKBOX_HLT')
|
||||||
|
row.operator(PsaExportActionsDeselectAll.bl_idname, text='None', icon='CHECKBOX_DEHLT')
|
||||||
|
|
||||||
# ACTIONS
|
# ACTIONS
|
||||||
if pg.sequence_source == 'ACTIONS':
|
if pg.sequence_source == 'ACTIONS':
|
||||||
layout.label(text='Actions', icon='ACTION')
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.label(text='Select')
|
|
||||||
row.operator(PsaExportActionsSelectAll.bl_idname, text='All')
|
|
||||||
row.operator(PsaExportActionsDeselectAll.bl_idname, text='None')
|
|
||||||
row = layout.row()
|
|
||||||
rows = max(3, min(len(pg.action_list), 10))
|
rows = max(3, min(len(pg.action_list), 10))
|
||||||
row.template_list('PSA_UL_ExportActionList', '', pg, 'action_list', pg, 'action_list_index', rows=rows)
|
layout.template_list('PSA_UL_ExportActionList', '', pg, 'action_list', pg, 'action_list_index', rows=rows)
|
||||||
|
|
||||||
col = layout.column(heading="Options")
|
col = layout.column()
|
||||||
col.use_property_split = True
|
col.use_property_split = True
|
||||||
col.use_property_decorate = False
|
col.use_property_decorate = False
|
||||||
col.prop(pg, 'should_use_original_sequence_names')
|
col.prop(pg, 'should_use_original_sequence_names')
|
||||||
elif pg.sequence_source == 'TIMELINE_MARKERS':
|
col.prop(pg, 'sequence_name_prefix')
|
||||||
layout.label(text='Markers', icon='MARKER')
|
col.prop(pg, 'sequence_name_suffix')
|
||||||
|
|
||||||
row = layout.row()
|
elif pg.sequence_source == 'TIMELINE_MARKERS':
|
||||||
rows = max(3, min(len(pg.marker_list), 10))
|
rows = max(3, min(len(pg.marker_list), 10))
|
||||||
row.template_list('PSA_UL_ExportTimelineMarkerList', '', pg, 'marker_list', pg, 'marker_list_index', rows=rows)
|
layout.template_list('PSA_UL_ExportTimelineMarkerList', '', pg, 'marker_list', pg, 'marker_list_index', rows=rows)
|
||||||
|
|
||||||
|
col = layout.column()
|
||||||
|
col.use_property_split = True
|
||||||
|
col.use_property_decorate = False
|
||||||
|
col.prop(pg, 'should_trim_timeline_marker_sequences')
|
||||||
|
col.prop(pg, 'sequence_name_prefix')
|
||||||
|
col.prop(pg, 'sequence_name_suffix')
|
||||||
|
|
||||||
# Determine if there is going to be a naming conflict and display an error, if so.
|
# Determine if there is going to be a naming conflict and display an error, if so.
|
||||||
selected_items = [x for x in pg.action_list if x.is_selected]
|
selected_items = [x for x in pg.action_list if x.is_selected]
|
||||||
@ -158,24 +168,16 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
# BONES
|
# BONES
|
||||||
box = layout.row()
|
row = layout.row(align=True)
|
||||||
box.label(text='Bones', icon='BONE_DATA')
|
row.prop(pg, 'bone_filter_mode', text='Bones')
|
||||||
bone_filter_mode_items = pg.bl_rna.properties['bone_filter_mode'].enum_items_static
|
|
||||||
row = box.row(align=True)
|
|
||||||
|
|
||||||
for item in bone_filter_mode_items:
|
|
||||||
identifier = item.identifier
|
|
||||||
item_layout = row.row(align=True)
|
|
||||||
item_layout.prop_enum(pg, 'bone_filter_mode', item.identifier)
|
|
||||||
item_layout.enabled = is_bone_filter_mode_item_available(context, identifier)
|
|
||||||
|
|
||||||
if pg.bone_filter_mode == 'BONE_GROUPS':
|
if pg.bone_filter_mode == 'BONE_GROUPS':
|
||||||
rows = max(3, min(len(pg.bone_group_list), 10))
|
|
||||||
layout.template_list('PSX_UL_BoneGroupList', '', pg, 'bone_group_list', pg, 'bone_group_list_index', rows=rows)
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text='Select')
|
row.label(text='Select')
|
||||||
row.operator(PsaExportBoneGroupsSelectAll.bl_idname, text='All')
|
row.operator(PsaExportBoneGroupsSelectAll.bl_idname, text='All', icon='CHECKBOX_HLT')
|
||||||
row.operator(PsaExportBoneGroupsDeselectAll.bl_idname, text='None')
|
row.operator(PsaExportBoneGroupsDeselectAll.bl_idname, text='None', icon='CHECKBOX_DEHLT')
|
||||||
|
rows = max(3, min(len(pg.bone_group_list), 10))
|
||||||
|
layout.template_list('PSX_UL_BoneGroupList', '', pg, 'bone_group_list', pg, 'bone_group_list_index', rows=rows)
|
||||||
|
|
||||||
def is_action_for_armature(self, action):
|
def is_action_for_armature(self, action):
|
||||||
if len(action.fcurves) == 0:
|
if len(action.fcurves) == 0:
|
||||||
@ -246,6 +248,10 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
options.bone_filter_mode = pg.bone_filter_mode
|
options.bone_filter_mode = pg.bone_filter_mode
|
||||||
options.bone_group_indices = [x.index for x in pg.bone_group_list if x.is_selected]
|
options.bone_group_indices = [x.index for x in pg.bone_group_list if x.is_selected]
|
||||||
options.should_use_original_sequence_names = pg.should_use_original_sequence_names
|
options.should_use_original_sequence_names = pg.should_use_original_sequence_names
|
||||||
|
options.should_trim_timeline_marker_sequences = pg.should_trim_timeline_marker_sequences
|
||||||
|
options.sequence_name_prefix = pg.sequence_name_prefix
|
||||||
|
options.sequence_name_suffix = pg.sequence_name_suffix
|
||||||
|
|
||||||
builder = PsaBuilder()
|
builder = PsaBuilder()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -261,9 +267,7 @@ class PsaExportOperator(Operator, ExportHelper):
|
|||||||
|
|
||||||
class PSA_UL_ExportTimelineMarkerList(UIList):
|
class PSA_UL_ExportTimelineMarkerList(UIList):
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||||
layout.alignment = 'LEFT'
|
layout.prop(item, 'is_selected', icon_only=True, text=item.marker_name)
|
||||||
layout.prop(item, 'is_selected', icon_only=True)
|
|
||||||
layout.label(text=item.marker_name)
|
|
||||||
|
|
||||||
def filter_items(self, context, data, property):
|
def filter_items(self, context, data, property):
|
||||||
actions = getattr(data, property)
|
actions = getattr(data, property)
|
||||||
@ -282,9 +286,7 @@ class PSA_UL_ExportTimelineMarkerList(UIList):
|
|||||||
|
|
||||||
class PSA_UL_ExportActionList(UIList):
|
class PSA_UL_ExportActionList(UIList):
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||||
layout.alignment = 'LEFT'
|
layout.prop(item, 'is_selected', icon_only=True, text=item.action_name)
|
||||||
layout.prop(item, 'is_selected', icon_only=True)
|
|
||||||
layout.label(text=item.action_name)
|
|
||||||
|
|
||||||
def filter_items(self, context, data, property):
|
def filter_items(self, context, data, property):
|
||||||
actions = getattr(data, property)
|
actions = getattr(data, property)
|
||||||
@ -302,41 +304,57 @@ class PSA_UL_ExportActionList(UIList):
|
|||||||
|
|
||||||
|
|
||||||
class PsaExportActionsSelectAll(Operator):
|
class PsaExportActionsSelectAll(Operator):
|
||||||
bl_idname = 'psa_export.actions_select_all'
|
bl_idname = 'psa_export.sequences_select_all'
|
||||||
bl_label = 'Select All'
|
bl_label = 'Select All'
|
||||||
bl_description = 'Select all actions'
|
bl_description = 'Select all sequences'
|
||||||
bl_options = {'INTERNAL'}
|
bl_options = {'INTERNAL'}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def get_item_list(cls, context):
|
||||||
pg = context.scene.psa_export
|
pg = context.scene.psa_export
|
||||||
item_list = pg.action_list
|
if pg.sequence_source == 'ACTIONS':
|
||||||
|
return pg.action_list
|
||||||
|
elif pg.sequence_source == 'TIMELINE_MARKERS':
|
||||||
|
return pg.marker_list
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
item_list = cls.get_item_list(context)
|
||||||
has_unselected_items = any(map(lambda item: not item.is_selected, item_list))
|
has_unselected_items = any(map(lambda item: not item.is_selected, item_list))
|
||||||
return len(item_list) > 0 and has_unselected_items
|
return len(item_list) > 0 and has_unselected_items
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
pg = context.scene.psa_export
|
item_list = self.get_item_list(context)
|
||||||
for item in pg.action_list:
|
for item in item_list:
|
||||||
item.is_selected = True
|
item.is_selected = True
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class PsaExportActionsDeselectAll(Operator):
|
class PsaExportActionsDeselectAll(Operator):
|
||||||
bl_idname = 'psa_export.actions_deselect_all'
|
bl_idname = 'psa_export.sequences_deselect_all'
|
||||||
bl_label = 'Deselect All'
|
bl_label = 'Deselect All'
|
||||||
bl_description = 'Deselect all actions'
|
bl_description = 'Deselect all sequences'
|
||||||
bl_options = {'INTERNAL'}
|
bl_options = {'INTERNAL'}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def get_item_list(cls, context):
|
||||||
pg = context.scene.psa_export
|
pg = context.scene.psa_export
|
||||||
item_list = pg.action_list
|
if pg.sequence_source == 'ACTIONS':
|
||||||
|
return pg.action_list
|
||||||
|
elif pg.sequence_source == 'TIMELINE_MARKERS':
|
||||||
|
return pg.marker_list
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
item_list = cls.get_item_list(context)
|
||||||
has_selected_items = any(map(lambda item: item.is_selected, item_list))
|
has_selected_items = any(map(lambda item: item.is_selected, item_list))
|
||||||
return len(item_list) > 0 and has_selected_items
|
return len(item_list) > 0 and has_selected_items
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
pg = context.scene.psa_export
|
item_list = self.get_item_list(context)
|
||||||
for item in pg.action_list:
|
for item in item_list:
|
||||||
item.is_selected = False
|
item.is_selected = False
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ class PsaImporter(object):
|
|||||||
sequence_data_matrix[frame_index, bone_index] = calculate_fcurve_data(import_bone, key_data)
|
sequence_data_matrix[frame_index, bone_index] = calculate_fcurve_data(import_bone, key_data)
|
||||||
|
|
||||||
# Clean the keyframe data. This is accomplished by writing zeroes to the write matrix when there is an
|
# Clean the keyframe data. This is accomplished by writing zeroes to the write matrix when there is an
|
||||||
# insufficiently large change in the data from frame-to-frame.
|
# insufficiently large change in the data from the last written frame.
|
||||||
if options.should_clean_keys:
|
if options.should_clean_keys:
|
||||||
threshold = 0.001
|
threshold = 0.001
|
||||||
for bone_index, import_bone in enumerate(import_bones):
|
for bone_index, import_bone in enumerate(import_bones):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user