auto_walk/OP_animate_path.py

122 lines
4.0 KiB
Python
Raw Normal View History

2021-04-05 01:35:12 +02:00
import bpy
from . import fn
from . import animate_path
class WCA_OT_animate_path(bpy.types.Operator):
bl_idname = "anim.animate_path"
bl_label = "Animate Path"
bl_description = "Select the most representative 'in contact' feet of the cycle"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
# def invoke(self, context, event):
# self.shift = event.shift
# return self.execute(context)
def execute(self, context):
# TODO clear previous animation (keys) if there is any
err = animate_path.anim_path_from_y_translate()
if err:
self.report({err[0]}, err[1])
if err[0] == 'ERROR':
return {"CANCELLED"}
return {"FINISHED"}
class WCA_OT_adjust_animation_length(bpy.types.Operator):
bl_idname = "anim.adjust_animation_length"
bl_label = "Adjust Anim speed"
bl_description = "Adjust speed\nOnce pressed, move up/down to move animation path last key value"
bl_options = {"REGISTER"} # , "UNDO"
@classmethod
def poll(cls, context):
return context.object and context.object.type in ('ARMATURE', 'CURVE')
val = bpy.props.FloatProperty(name='End key value')
def invoke(self, context, event):
# check animation data of curve
# self.pref = fn.get_addon_prefs()
curve = bpy.context.scene.anim_cycle_settings.path_to_follow
if not curve:
if context.object.type != 'ARMATURE':
self.report({'ERROR'}, 'no curve targeted in "Path" field')
return {"CANCELLED"}
curve, _const = fn.get_follow_curve_from_armature(obj)
if isinstance(curve, str):
self.report({curve}, _const)
return {"CANCELLED"}
self.act = fn.get_obj_action(curve.data)
if not self.act:
self.report({'ERROR'}, f'No action on {curve.name} data')
return {"CANCELLED"}
self.fcu = None
for fcu in self.act.fcurves:
if fcu.data_path == 'eval_time':
self.fcu = fcu
break
if not self.fcu or not len(self.fcu.keyframe_points):
self.report({'ERROR'}, f'No eval_time animated on {curve.name} data action (or no keys)')
return {"CANCELLED"}
if len(self.fcu.keyframe_points) > 2:
self.report({'WARNING'}, f'{curve.name} eval_time has {len(self.fcu.keyframe_points)} keyframe (should just have 2 to redefine speed)')
self.k = self.fcu.keyframe_points[-1]
self.val = self.init_ky = self.k.co.y
self.init_my = event.mouse_y
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
def modal(self, context, event):
# added reduction factor
self.val = self.init_ky + ((event.mouse_y - self.init_my) * 0.1)
offset = self.val - self.init_ky
display_text = f"Path animation end key value {self.val:.3f}, offset {offset:.3f}"
context.area.header_text_set(display_text)
self.k.co.y = self.val
if event.type == 'LEFTMOUSE' and event.value == "PRESS":
context.area.header_text_set(None)
self.execute(context)
return {"FINISHED"}
if event.type in ('RIGHTMOUSE', 'ESC') and event.value == "PRESS":
self.k.co.y = self.init_ky
context.area.header_text_set(None)
return {"CANCELLED"}
# return {'PASS_THROUGH'}
return {"RUNNING_MODAL"}
def execute(self, context):
self.k.co.y = self.val
return {"FINISHED"}
# def draw(self, context):
# layout = self.layout
# layout.prop(self, "val")
classes=(
WCA_OT_animate_path,
WCA_OT_adjust_animation_length,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)