1
0
mirror of https://github.com/DarklightGames/io_scene_psk_psa.git synced 2025-02-23 04:18:59 +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 import re
from collections import Counter from collections import Counter
from typing import List, Iterable, Dict, Tuple, Optional from typing import List, Iterable, Dict, Tuple, cast, Optional
import bpy import bpy
from bpy.props import StringProperty 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 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): def is_action_for_armature(armature: Armature, action: Action):
if len(action.fcurves) == 0: if len(action.fcurves) == 0:
return False return False
@ -30,12 +44,13 @@ def is_action_for_armature(armature: Armature, action: Action):
return False 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') pg = getattr(context.scene, 'psa_export')
# Clear actions and markers. # Clear actions and markers.
pg.action_list.clear() pg.action_list.clear()
pg.marker_list.clear() pg.marker_list.clear()
pg.active_action_list.clear()
# Get animation data. # Get animation data.
animation_data_object = get_animation_data_object(context) 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: if animation_data is None:
return return
active_armature = cast(Armature, context.active_object.data)
# Populate actions list. # Populate actions list.
for action in bpy.data.actions: for action in bpy.data.actions:
if not is_action_for_armature(armature, action): if not is_action_for_armature(active_armature, action):
continue continue
if action.name != '' and not action.name.startswith('#'): 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_start = frame_start
item.frame_end = frame_end 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: def get_sequence_fps(context: Context, fps_source: str, fps_custom: float, actions: Iterable[Action]) -> float:
match fps_source: match fps_source:
@ -229,7 +259,6 @@ class PSA_OT_export(Operator, ExportHelper):
flow.use_property_decorate = False flow.use_property_decorate = False
flow.prop(pg, 'sequence_source', text='Source') flow.prop(pg, 'sequence_source', text='Source')
if pg.sequence_source != 'ACTIVE_ACTION':
if pg.sequence_source in {'TIMELINE_MARKERS', 'NLA_TRACK_STRIPS'}: if pg.sequence_source in {'TIMELINE_MARKERS', 'NLA_TRACK_STRIPS'}:
# ANIMDATA SOURCE # ANIMDATA SOURCE
flow.prop(pg, 'should_override_animation_data') flow.prop(pg, 'should_override_animation_data')
@ -250,17 +279,6 @@ class PSA_OT_export(Operator, ExportHelper):
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) 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, sequences_panel.template_list(PSA_UL_export_sequences.bl_idname, '', pg, propname, pg, active_propname,
rows=max(3, min(len(getattr(pg, propname)), 10))) rows=max(3, min(len(getattr(pg, propname)), 10)))
@ -345,7 +363,7 @@ class PSA_OT_export(Operator, ExportHelper):
# data created before (i.e. if no action was ever assigned to it). # data created before (i.e. if no action was ever assigned to it).
self.armature_object.animation_data_create() 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) 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_sequence.key_quota = nla_strip_item.action.psa_export.key_quota
export_sequences.append(export_sequence) export_sequences.append(export_sequence)
case 'ACTIVE_ACTION': case 'ACTIVE_ACTION':
for obj in selected_armature_objects: for active_action_item in filter(lambda x: x.is_selected, pg.active_action_list):
if obj.animation_data is None or obj.animation_data.action is None: export_sequence = PsaBuildSequence(active_action_item.armature_object, active_action_item.armature_object.animation_data)
continue action = active_action_item.action
action = obj.animation_data.action
export_sequence = PsaBuildSequence(obj, obj.animation_data)
export_sequence.name = action.name export_sequence.name = action.name
export_sequence.nla_state.action = action export_sequence.nla_state.action = action
export_sequence.nla_state.frame_start = int(action.frame_range[0]) 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 return pg.marker_list
case 'NLA_TRACK_STRIPS': case 'NLA_TRACK_STRIPS':
return pg.nla_strip_list return pg.nla_strip_list
case 'ACTIVE_ACTION':
return pg.active_action_list
case _: case _:
return None return None
@ -471,6 +489,7 @@ class PSA_OT_export_actions_select_all(Operator):
def poll(cls, context): def poll(cls, context):
pg = getattr(context.scene, 'psa_export') pg = getattr(context.scene, 'psa_export')
item_list = cls.get_item_list(context) item_list = cls.get_item_list(context)
print(item_list)
visible_sequences = get_visible_sequences(pg, item_list) visible_sequences = get_visible_sequences(pg, item_list)
has_unselected_sequences = any(map(lambda item: not item.is_selected, visible_sequences)) has_unselected_sequences = any(map(lambda item: not item.is_selected, visible_sequences))
return has_unselected_sequences return has_unselected_sequences
@ -499,6 +518,8 @@ class PSA_OT_export_actions_deselect_all(Operator):
return pg.marker_list return pg.marker_list
case 'NLA_TRACK_STRIPS': case 'NLA_TRACK_STRIPS':
return pg.nla_strip_list return pg.nla_strip_list
case 'ACTIVE_ACTION':
return pg.active_action_list
case _: case _:
return None return None

View File

@ -27,6 +27,15 @@ class PSA_PG_export_action_list_item(PropertyGroup):
is_pose_marker: BoolProperty(options={'HIDDEN'}) 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 class PSA_PG_export_timeline_markers(PropertyGroup): # TODO: rename this to singular
marker_index: IntProperty() marker_index: IntProperty()
name: StringProperty() name: StringProperty()
@ -153,6 +162,8 @@ class PSA_PG_export(PropertyGroup):
marker_list_index: IntProperty(default=0) marker_list_index: IntProperty(default=0)
nla_strip_list: CollectionProperty(type=PSA_PG_export_nla_strip_list_item) nla_strip_list: CollectionProperty(type=PSA_PG_export_nla_strip_list_item)
nla_strip_list_index: IntProperty(default=0) 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( bone_filter_mode: EnumProperty(
name='Bone Filter', name='Bone Filter',
options=empty_set, options=empty_set,
@ -235,5 +246,6 @@ classes = (
PSA_PG_export_action_list_item, PSA_PG_export_action_list_item,
PSA_PG_export_timeline_markers, PSA_PG_export_timeline_markers,
PSA_PG_export_nla_strip_list_item, PSA_PG_export_nla_strip_list_item,
PSA_PG_export_active_action_list_item,
PSA_PG_export, 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): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
item = typing.cast(PSA_PG_export_action_list_item, item) item = typing.cast(PSA_PG_export_action_list_item, item)
is_pose_marker = hasattr(item, 'is_pose_marker') and item.is_pose_marker is_pose_marker = hasattr(item, 'is_pose_marker') and item.is_pose_marker
layout.prop(item, 'is_selected', icon_only=True, text=item.name) 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: 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: if is_pose_marker:
row.label(text=item.action.name, icon='PMARKER') 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): def draw_filter(self, context, layout):
pg = getattr(context.scene, 'psa_export') pg = getattr(context.scene, 'psa_export')
row = layout.row() row = layout.row()