1
0
mirror of https://github.com/DarklightGames/io_scene_psk_psa.git synced 2025-02-22 11:59:55 +01:00

Added an export list to the PSA export dialog for active actions

This commit is contained in:
Colin Basnett 2024-12-08 14:43:37 -08:00
parent 491e042cec
commit ef559d9475
3 changed files with 77 additions and 40 deletions

View File

@ -1,6 +1,6 @@
import re
from collections import Counter
from typing import List, Iterable, Dict, Tuple, Optional
from typing import List, Iterable, Dict, Tuple, cast, Optional
import bpy
from bpy.props import StringProperty
@ -16,6 +16,20 @@ from ...shared.helpers import populate_bone_collection_list, get_nla_strips_in_f
from ...shared.ui import draw_bone_filter_mode
def get_sequences_propnames_from_source(sequence_source: str) -> Optional[Tuple[str, str]]:
match sequence_source:
case 'ACTIONS':
return 'action_list', 'action_list_index'
case 'TIMELINE_MARKERS':
return 'marker_list', 'marker_list_index'
case 'NLA_TRACK_STRIPS':
return 'nla_strip_list', 'nla_strip_list_index'
case 'ACTIVE_ACTION':
return 'active_action_list', 'active_action_list_index'
case _:
raise ValueError(f'Unhandled sequence source: {sequence_source}')
def is_action_for_armature(armature: Armature, action: Action):
if len(action.fcurves) == 0:
return False
@ -30,12 +44,13 @@ def is_action_for_armature(armature: Armature, action: Action):
return False
def update_actions_and_timeline_markers(context: Context, armature: Armature):
def update_actions_and_timeline_markers(context: Context):
pg = getattr(context.scene, 'psa_export')
# Clear actions and markers.
pg.action_list.clear()
pg.marker_list.clear()
pg.active_action_list.clear()
# Get animation data.
animation_data_object = get_animation_data_object(context)
@ -44,9 +59,11 @@ def update_actions_and_timeline_markers(context: Context, armature: Armature):
if animation_data is None:
return
active_armature = cast(Armature, context.active_object.data)
# Populate actions list.
for action in bpy.data.actions:
if not is_action_for_armature(armature, action):
if not is_action_for_armature(active_armature, action):
continue
if action.name != '' and not action.name.startswith('#'):
@ -91,6 +108,19 @@ def update_actions_and_timeline_markers(context: Context, armature: Armature):
item.frame_start = frame_start
item.frame_end = frame_end
# Populate the active action list.
for armature_object in context.selected_objects:
if armature_object.type != 'ARMATURE':
continue
action = armature_object.animation_data.action
item = pg.active_action_list.add()
item.name = action.name
item.armature_object = armature_object
item.action = action
item.frame_start = int(item.action.frame_range[0])
item.frame_end = int(item.action.frame_range[1])
item.is_selected = True
def get_sequence_fps(context: Context, fps_source: str, fps_custom: float, actions: Iterable[Action]) -> float:
match fps_source:
@ -229,41 +259,29 @@ class PSA_OT_export(Operator, ExportHelper):
flow.use_property_decorate = False
flow.prop(pg, 'sequence_source', text='Source')
if pg.sequence_source != 'ACTIVE_ACTION':
if pg.sequence_source in {'TIMELINE_MARKERS', 'NLA_TRACK_STRIPS'}:
# ANIMDATA SOURCE
flow.prop(pg, 'should_override_animation_data')
if pg.should_override_animation_data:
flow.prop(pg, 'animation_data_override', text=' ')
if pg.sequence_source in {'TIMELINE_MARKERS', 'NLA_TRACK_STRIPS'}:
# ANIMDATA SOURCE
flow.prop(pg, 'should_override_animation_data')
if pg.should_override_animation_data:
flow.prop(pg, 'animation_data_override', text=' ')
if pg.sequence_source == 'NLA_TRACK_STRIPS':
flow = sequences_panel.grid_flow()
flow.use_property_split = True
flow.use_property_decorate = False
flow.prop(pg, 'nla_track')
if pg.sequence_source == 'NLA_TRACK_STRIPS':
flow = sequences_panel.grid_flow()
flow.use_property_split = True
flow.use_property_decorate = False
flow.prop(pg, 'nla_track')
# SELECT ALL/NONE
row = sequences_panel.row(align=True)
row.label(text='Select')
row.operator(PSA_OT_export_actions_select_all.bl_idname, text='All', icon='CHECKBOX_HLT')
row.operator(PSA_OT_export_actions_deselect_all.bl_idname, text='None', icon='CHECKBOX_DEHLT')
# SELECT ALL/NONE
row = sequences_panel.row(align=True)
row.label(text='Select')
row.operator(PSA_OT_export_actions_select_all.bl_idname, text='All', icon='CHECKBOX_HLT')
row.operator(PSA_OT_export_actions_deselect_all.bl_idname, text='None', icon='CHECKBOX_DEHLT')
from .ui import PSA_UL_export_sequences
from .ui import PSA_UL_export_sequences
def get_sequences_propnames_from_source(sequence_source: str) -> Optional[Tuple[str, str]]:
match sequence_source:
case 'ACTIONS':
return 'action_list', 'action_list_index'
case 'TIMELINE_MARKERS':
return 'marker_list', 'marker_list_index'
case 'NLA_TRACK_STRIPS':
return 'nla_strip_list', 'nla_strip_list_index'
case _:
raise ValueError(f'Unhandled sequence source: {sequence_source}')
propname, active_propname = get_sequences_propnames_from_source(pg.sequence_source)
sequences_panel.template_list(PSA_UL_export_sequences.bl_idname, '', pg, propname, pg, active_propname,
rows=max(3, min(len(getattr(pg, propname)), 10)))
propname, active_propname = get_sequences_propnames_from_source(pg.sequence_source)
sequences_panel.template_list(PSA_UL_export_sequences.bl_idname, '', pg, propname, pg, active_propname,
rows=max(3, min(len(getattr(pg, propname)), 10)))
flow = sequences_panel.grid_flow()
flow.use_property_split = True
@ -345,7 +363,7 @@ class PSA_OT_export(Operator, ExportHelper):
# data created before (i.e. if no action was ever assigned to it).
self.armature_object.animation_data_create()
update_actions_and_timeline_markers(context, self.armature_object.data)
update_actions_and_timeline_markers(context)
populate_bone_collection_list(self.armature_object, pg.bone_collection_list)
@ -410,11 +428,9 @@ class PSA_OT_export(Operator, ExportHelper):
export_sequence.key_quota = nla_strip_item.action.psa_export.key_quota
export_sequences.append(export_sequence)
case 'ACTIVE_ACTION':
for obj in selected_armature_objects:
if obj.animation_data is None or obj.animation_data.action is None:
continue
action = obj.animation_data.action
export_sequence = PsaBuildSequence(obj, obj.animation_data)
for active_action_item in filter(lambda x: x.is_selected, pg.active_action_list):
export_sequence = PsaBuildSequence(active_action_item.armature_object, active_action_item.armature_object.animation_data)
action = active_action_item.action
export_sequence.name = action.name
export_sequence.nla_state.action = action
export_sequence.nla_state.frame_start = int(action.frame_range[0])
@ -464,6 +480,8 @@ class PSA_OT_export_actions_select_all(Operator):
return pg.marker_list
case 'NLA_TRACK_STRIPS':
return pg.nla_strip_list
case 'ACTIVE_ACTION':
return pg.active_action_list
case _:
return None
@ -471,6 +489,7 @@ class PSA_OT_export_actions_select_all(Operator):
def poll(cls, context):
pg = getattr(context.scene, 'psa_export')
item_list = cls.get_item_list(context)
print(item_list)
visible_sequences = get_visible_sequences(pg, item_list)
has_unselected_sequences = any(map(lambda item: not item.is_selected, visible_sequences))
return has_unselected_sequences
@ -499,6 +518,8 @@ class PSA_OT_export_actions_deselect_all(Operator):
return pg.marker_list
case 'NLA_TRACK_STRIPS':
return pg.nla_strip_list
case 'ACTIVE_ACTION':
return pg.active_action_list
case _:
return None

View File

@ -27,6 +27,15 @@ class PSA_PG_export_action_list_item(PropertyGroup):
is_pose_marker: BoolProperty(options={'HIDDEN'})
class PSA_PG_export_active_action_list_item(PropertyGroup):
action: PointerProperty(type=Action)
name: StringProperty()
armature_object: PointerProperty(type=Object)
is_selected: BoolProperty(default=True)
frame_start: IntProperty(options={'HIDDEN'})
frame_end: IntProperty(options={'HIDDEN'})
class PSA_PG_export_timeline_markers(PropertyGroup): # TODO: rename this to singular
marker_index: IntProperty()
name: StringProperty()
@ -153,6 +162,8 @@ class PSA_PG_export(PropertyGroup):
marker_list_index: IntProperty(default=0)
nla_strip_list: CollectionProperty(type=PSA_PG_export_nla_strip_list_item)
nla_strip_list_index: IntProperty(default=0)
active_action_list: CollectionProperty(type=PSA_PG_export_active_action_list_item)
active_action_list_index: IntProperty(default=0)
bone_filter_mode: EnumProperty(
name='Bone Filter',
options=empty_set,
@ -235,5 +246,6 @@ classes = (
PSA_PG_export_action_list_item,
PSA_PG_export_timeline_markers,
PSA_PG_export_nla_strip_list_item,
PSA_PG_export_active_action_list_item,
PSA_PG_export,
)

View File

@ -15,6 +15,7 @@ class PSA_UL_export_sequences(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
item = typing.cast(PSA_PG_export_action_list_item, item)
is_pose_marker = hasattr(item, 'is_pose_marker') and item.is_pose_marker
layout.prop(item, 'is_selected', icon_only=True, text=item.name)
if hasattr(item, 'action') and item.action is not None and item.action.asset_data is not None:
@ -27,6 +28,9 @@ class PSA_UL_export_sequences(UIList):
if is_pose_marker:
row.label(text=item.action.name, icon='PMARKER')
if hasattr(item, 'armature_object') and item.armature_object is not None:
row.label(text=item.armature_object.name, icon='ARMATURE_DATA')
def draw_filter(self, context, layout):
pg = getattr(context.scene, 'psa_export')
row = layout.row()