metaforce/hecl/blender/addon/sact/SACTEvent.py

445 lines
21 KiB
Python

import bpy
# Loop event class
class hecl_actor_event_loop(bpy.types.PropertyGroup):
bool = bpy.props.BoolProperty(name="Loop Bool")
# UEVT event class
class hecl_actor_event_uevt(bpy.types.PropertyGroup):
type = bpy.props.IntProperty(name="UEVT Type")
bone_name = bpy.props.StringProperty(name="Bone Name")
# Effect event class
class hecl_actor_event_effect(bpy.types.PropertyGroup):
frame_count = bpy.props.IntProperty(name="Frame Count", min=0)
uid = bpy.props.StringProperty(name="Effect UID")
bone_name = bpy.props.StringProperty(name="Bone Name")
scale = bpy.props.FloatProperty(name="Scale", description="Proportional spacial scale")
transform_mode = bpy.props.EnumProperty(name="Transform Mode", description="How the bone will transform the effect",
items=[('STATIONARY', "Stationary", "Effect emitter will be transformed in bone-space, then retained"),
('WORLD', "World", "Effect emitter will be transformed in bone-space"),
('LOCAL', "Local", "Entire effect will be transformed in bone-space")])
# Sound event class
class hecl_actor_event_sound(bpy.types.PropertyGroup):
sound_id = bpy.props.StringProperty(name="Sound ID")
ref_amp = bpy.props.FloatProperty(name="Reference Amplitude")
ref_dist = bpy.props.FloatProperty(name="Reference Distance")
# Name update
def update_name(self, context):
if bpy.context.scene.hecl_type == 'ACTOR':
clear_event_markers(bpy.context.scene.hecl_sact_data, context)
update_action_events(None)
active_event_update(self, context)
# Actor event class
class hecl_actor_event(bpy.types.PropertyGroup):
name = bpy.props.StringProperty(name="Event Name",
update=update_name)
type = bpy.props.EnumProperty(name="Event Type",
items=[('LOOP', "Loop", "Loop Event"),
('UEVT', "UEVT", "UEVT Event"),
('EFFECT', "Effect", "Effect Event"),
('SOUND', "Sound", "Sound Event")],
default='LOOP')
index = bpy.props.IntProperty(name="Event Index")
time = bpy.props.FloatProperty(name="Event Time")
props = bpy.props.StringProperty(name="Event props")
loop_data = bpy.props.PointerProperty(name="Loop event data",
type=hecl_actor_event_loop)
uevt_data = bpy.props.PointerProperty(name="UEVT event data",
type=hecl_actor_event_uevt)
effect_data = bpy.props.PointerProperty(name="Effect event data",
type=hecl_actor_event_effect)
sound_data = bpy.props.PointerProperty(name="Sound event data",
type=hecl_actor_event_sound)
# Panel draw
def draw(layout, context):
actor_data = context.scene.hecl_sact_data
armature = None
if actor_data.active_subtype >= 0:
if actor_data.active_subtype in range(len(actor_data.subtypes)):
subtype = actor_data.subtypes[actor_data.active_subtype]
if subtype and subtype.linked_armature in bpy.data.objects:
armature = bpy.data.objects[subtype.linked_armature]
row = layout.row(align=True)
row.alignment = 'LEFT'
row.prop(actor_data, 'show_events', text="Events", icon='PREVIEW_RANGE', emboss=False)
if actor_data.show_events:
# Get action
action_data = None
subaction_data = None
if actor_data.active_action in range(len(actor_data.actions)):
action_data = actor_data.actions[actor_data.active_action]
if action_data.type == 'SINGLE':
subaction_data = action_data.subactions[0]
elif action_data.type == 'SEQUENCE' or action_data.type == 'RANDOM':
if action_data.active_subaction in range(len(action_data.subactions)):
subaction_data = action_data.subactions[action_data.active_subaction]
# Validate
if subaction_data is None:
layout.label("(Sub)action not selected in 'Actions'", icon='ERROR')
else:
if subaction_data.name == '':
layout.label("Action not set", icon='ERROR')
elif subaction_data.name not in bpy.data.actions:
layout.label("Action '"+subaction_data.name+"' not found", icon='ERROR')
else:
action = bpy.data.actions[subaction_data.name]
# Event list
row = layout.row()
row.template_list("UI_UL_list", "SCENE_UL_hecl_actor_subaction_events",
action, 'hecl_events', action, 'hecl_active_event')
col = row.column(align=True)
col.operator("scene.hecl_actor_subaction_event_add", icon="ZOOMIN", text="")
col.operator("scene.hecl_actor_subaction_event_remove", icon="ZOOMOUT", text="")
col.separator()
col.operator("scene.hecl_actor_subaction_event_move_up", icon="TRIA_UP", text="")
col.operator("scene.hecl_actor_subaction_event_move_down", icon="TRIA_DOWN", text="")
if len(action.hecl_events) and action.hecl_active_event >= 0:
event = action.hecl_events[action.hecl_active_event]
layout.prop(event, 'name', text="Name")
layout.prop(event, 'index', text="Index")
layout.prop(event, 'props', text="Props")
layout.label('Marker Time: ' + '{:g}'.format(event.time), icon='MARKER_HLT')
layout.label("Event Type:")
row = layout.row(align=True)
row.prop_enum(event, 'type', 'LOOP')
row.prop_enum(event, 'type', 'UEVT')
row.prop_enum(event, 'type', 'EFFECT')
row.prop_enum(event, 'type', 'SOUND')
if event.type == 'LOOP':
loop_data = event.loop_data
layout.prop(loop_data, 'bool')
elif event.type == 'UEVT':
uevt_data = event.uevt_data
layout.prop(uevt_data, 'type')
layout.prop(uevt_data, 'bone_name')
elif event.type == 'EFFECT':
effect_data = event.effect_data
layout.prop(effect_data, 'frame_count')
layout.prop(effect_data, 'uid')
if armature:
layout.prop_search(effect_data, 'bone_name', armature.data, 'bones')
else:
layout.prop(effect_data, 'bone_name')
layout.prop(effect_data, 'scale')
row = layout.row(align=True)
row.prop_enum(effect_data, 'transform_mode', 'STATIONARY')
row.prop_enum(effect_data, 'transform_mode', 'WORLD')
row.prop_enum(effect_data, 'transform_mode', 'LOCAL')
elif event.type == 'SOUND':
sound_data = event.sound_data
layout.prop(sound_data, 'sound_id')
layout.prop(sound_data, 'ref_amp')
layout.prop(sound_data, 'ref_dist')
# Clear event markers not in active event
def clear_event_markers(actor_data, context):
for marker in context.scene.timeline_markers:
if marker.name.startswith('hecl_'):
context.scene.timeline_markers.remove(marker)
# Event marker update
@bpy.app.handlers.persistent
def update_action_events(dummy):
context = bpy.context
if context.scene.hecl_type == 'ACTOR':
actor_data = context.scene.hecl_sact_data
if actor_data.active_action in range(len(actor_data.actions)):
action_data = actor_data.actions[actor_data.active_action]
if action_data.action in bpy.data.actions:
action_obj =\
bpy.data.actions[action_data.action]
for i in range(len(action_obj.hecl_events)):
event = action_obj.hecl_events[i]
marker_name = 'hecl_' + str(action_obj.hecl_index) + '_' + str(i) + '_' + event.name
if marker_name in context.scene.timeline_markers:
marker = context.scene.timeline_markers[marker_name]
event_time = marker.frame / action_obj.hecl_fps
if event_time != event.time:
event.time = event_time
else:
marker = context.scene.timeline_markers.new(marker_name)
marker.frame = event.time * action_obj.hecl_fps
marker.select = False
if i != action_obj.hecl_active_event and marker.select:
action_obj.hecl_active_event = i
# Event 'add' operator
class hecl_actor_subaction_event_add(bpy.types.Operator):
bl_idname = "scene.hecl_actor_subaction_event_add"
bl_label = "New HECL Actor Event"
bl_description = "Add New HECL Actor Event to active Sub-action"
@classmethod
def poll(cls, context):
actor_data = context.scene.hecl_sact_data
check = (context.scene is not None and
not context.scene.library and
context.scene.hecl_type == 'ACTOR' and
len(actor_data.actions) and
actor_data.active_action >= 0 and
len(actor_data.actions[actor_data.active_action].subactions) and
actor_data.actions[actor_data.active_action].active_subaction >= 0)
if not check:
return False
actor_data = context.scene.hecl_sact_data
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
return subaction_data.name in bpy.data.actions
def execute(self, context):
actor_data = context.scene.hecl_sact_data
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
blend_action = bpy.data.actions[subaction_data.name]
event_name = 'SubactionEvent'
if event_name in blend_action.hecl_events:
event_name = 'SubactionEvent.001'
event_idx = 1
while event_name in blend_action.hecl_events:
event_idx += 1
event_name = 'SubactionEvent.{:0>3}'.format(event_idx)
event = blend_action.hecl_events.add()
event.name = event_name
action_obj =\
bpy.data.actions[subaction_data.name]
event.time = (context.scene.frame_current / (context.scene.render.frame_map_new / context.scene.render.frame_map_old)) / action_obj.hecl_fps
blend_action.hecl_active_event = len(blend_action.hecl_events)-1
if not bpy.app.background:
update_action_events(None)
active_event_update(self, context)
return {'FINISHED'}
# Event 'remove' operator
class hecl_actor_subaction_event_remove(bpy.types.Operator):
bl_idname = "scene.hecl_actor_subaction_event_remove"
bl_label = "Remove HECL Actor Event"
bl_description = "Remove HECL Actor Event from active Sub-action"
@classmethod
def poll(cls, context):
actor_data = context.scene.hecl_sact_data
check = (context.scene is not None and
not context.scene.library and
context.scene.hecl_type == 'ACTOR' and
len(actor_data.actions) and
actor_data.active_action >= 0 and
len(actor_data.actions[actor_data.active_action].subactions) and
actor_data.actions[actor_data.active_action].active_subaction >= 0)
if not check:
return False
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
if subaction_data.name not in bpy.data.actions:
return False
blend_action = bpy.data.actions[subaction_data.name]
return blend_action.hecl_active_event in range(len(blend_action.hecl_events))
def execute(self, context):
actor_data = context.scene.hecl_sact_data
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
blend_action = bpy.data.actions[subaction_data.name]
event_name = blend_action.hecl_events[blend_action.hecl_active_event].name
blend_action.hecl_events.remove(blend_action.hecl_active_event)
marker_name = 'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event) + '_' + event_name
if marker_name in context.scene.timeline_markers:
context.scene.timeline_markers.remove(context.scene.timeline_markers[marker_name])
blend_action.hecl_active_event -= 1
if blend_action.hecl_active_event == -1:
blend_action.hecl_active_event = 0
clear_event_markers(actor_data, context)
return {'FINISHED'}
# Event 'move down' operator
class hecl_actor_subaction_event_move_down(bpy.types.Operator):
bl_idname = "scene.hecl_actor_subaction_event_move_down"
bl_label = "Move HECL Actor Event Down in Stack"
bl_description = "Move HECL Actor Event down in stack from active Sub-action"
@classmethod
def poll(cls, context):
actor_data = context.scene.hecl_sact_data
check = (context.scene is not None and
not context.scene.library and
context.scene.hecl_type == 'ACTOR' and
len(actor_data.actions) and
actor_data.active_action >= 0 and
len(actor_data.actions[actor_data.active_action].subactions) and
actor_data.actions[actor_data.active_action].active_subaction >= 0)
if not check:
return False
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
if subaction_data.name not in bpy.data.actions:
return False
blend_action = bpy.data.actions[subaction_data.name]
return (blend_action.hecl_active_event in range(len(blend_action.hecl_events)) and
blend_action.hecl_active_event < len(blend_action.hecl_events) - 1)
def execute(self, context):
actor_data = context.scene.hecl_sact_data
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
blend_action = bpy.data.actions[subaction_data.name]
event_name_a = blend_action.hecl_events[blend_action.hecl_active_event].name
event_name_b = blend_action.hecl_events[blend_action.hecl_active_event + 1].name
blend_action.hecl_events.move(blend_action.hecl_active_event, blend_action.hecl_active_event + 1)
marker_name_a = 'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event) + '_' + event_name_a
marker_a = None
if marker_name_a in context.scene.timeline_markers:
marker_a = context.scene.timeline_markers[marker_name_a]
marker_name_b = 'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event + 1) + '_' + event_name_b
marker_b = None
if marker_name_b in context.scene.timeline_markers:
marker_b = context.scene.timeline_markers[marker_name_b]
if marker_a and marker_b:
marker_a.name =\
'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event + 1) + '_' + event_name_a
marker_b.name =\
'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event) + '_' + event_name_b
blend_action.hecl_active_event += 1
return {'FINISHED'}
# Event 'move up' operator
class hecl_actor_subaction_event_move_up(bpy.types.Operator):
bl_idname = "scene.hecl_actor_subaction_event_move_up"
bl_label = "Move HECL Actor Event Up in Stack"
bl_description = "Move HECL Actor Event up in stack from active Sub-action"
@classmethod
def poll(cls, context):
actor_data = context.scene.hecl_sact_data
check = (context.scene is not None and
not context.scene.library and
context.scene.hecl_type == 'ACTOR' and
len(actor_data.actions) and
actor_data.active_action >= 0 and
len(actor_data.actions[actor_data.active_action].subactions) and
actor_data.actions[actor_data.active_action].active_subaction >= 0)
if not check:
return False
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
if subaction_data.name not in bpy.data.actions:
return False
blend_action = bpy.data.actions[subaction_data.name]
return (blend_action.hecl_active_event in range(len(blend_action.hecl_events)) and
blend_action.hecl_active_event > 0)
def execute(self, context):
actor_data = context.scene.hecl_sact_data
action_data = actor_data.actions[actor_data.active_action]
subaction_data = action_data.subactions[action_data.active_subaction]
blend_action = bpy.data.actions[subaction_data.name]
event_name_a = blend_action.hecl_events[blend_action.hecl_active_event].name
event_name_b = blend_action.hecl_events[blend_action.hecl_active_event - 1].name
blend_action.hecl_events.move(blend_action.hecl_active_event, blend_action.hecl_active_event - 1)
marker_name_a = 'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event) + '_' + event_name_a
marker_a = None
if marker_name_a in context.scene.timeline_markers:
marker_a = context.scene.timeline_markers[marker_name_a]
marker_name_b = 'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event - 1) + '_' + event_name_b
marker_b = None
if marker_name_b in context.scene.timeline_markers:
marker_b = context.scene.timeline_markers[marker_name_b]
if marker_a and marker_b:
marker_a.name =\
'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event - 1) + '_' + event_name_a
marker_b.name =\
'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event) + '_' + event_name_b
blend_action.hecl_active_event -= 1
return {'FINISHED'}
def active_event_update(self, context):
actor_data = context.scene.hecl_sact_data
if actor_data.active_action in range(len(actor_data.actions)):
action_data = actor_data.actions[actor_data.active_action]
if action_data.active_subaction in range(len(action_data.subactions)):
subaction_data = action_data.subactions[action_data.active_subaction]
for marker in context.scene.timeline_markers:
if marker.name.startswith('hecl_'):
blend_action = bpy.data.actions[subaction_data.name]
event_name = blend_action.hecl_events[blend_action.hecl_active_event].name
if marker.name == 'hecl_' + str(blend_action.hecl_index) + '_' + str(blend_action.hecl_active_event) + '_' + event_name:
marker.select = True
else:
marker.select = False
# Registration
def register():
bpy.utils.register_class(hecl_actor_event_loop)
bpy.utils.register_class(hecl_actor_event_uevt)
bpy.utils.register_class(hecl_actor_event_effect)
bpy.utils.register_class(hecl_actor_event_sound)
bpy.utils.register_class(hecl_actor_event)
bpy.utils.register_class(hecl_actor_subaction_event_add)
bpy.utils.register_class(hecl_actor_subaction_event_remove)
bpy.utils.register_class(hecl_actor_subaction_event_move_down)
bpy.utils.register_class(hecl_actor_subaction_event_move_up)
bpy.types.Action.hecl_events = bpy.props.CollectionProperty(name="HECL action event",
type=hecl_actor_event)
bpy.types.Action.hecl_active_event = bpy.props.IntProperty(name="HECL active action event",
default=0,
update=active_event_update)
if not bpy.app.background and update_action_events not in bpy.app.handlers.scene_update_post:
bpy.app.handlers.scene_update_post.append(update_action_events)
def unregister():
if update_action_events in bpy.app.handlers.scene_update_post:
bpy.app.handlers.scene_update_post.remove(update_action_events)
bpy.utils.unregister_class(hecl_actor_event)
bpy.utils.unregister_class(hecl_actor_event_loop)
bpy.utils.unregister_class(hecl_actor_event_uevt)
bpy.utils.unregister_class(hecl_actor_event_effect)
bpy.utils.unregister_class(hecl_actor_event_sound)
bpy.utils.unregister_class(hecl_actor_subaction_event_add)
bpy.utils.unregister_class(hecl_actor_subaction_event_remove)
bpy.utils.unregister_class(hecl_actor_subaction_event_move_down)
bpy.utils.unregister_class(hecl_actor_subaction_event_move_up)