Skip to content
Draft
61 changes: 35 additions & 26 deletions anim_offset/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,12 @@ def magnet_handlers(scene):

for obj in selected_objects:
action = getattr(obj.animation_data, 'action', None)
fcurves = utils.curve.get_fcurves_for_action(action)
fcurves_list = utils.curve.get_fcurves_list(fcurves) if fcurves else []

for fcurve in getattr(action, 'fcurves', list()):
for fcurve in fcurves_list:
if fcurve.data_path.endswith("rotation_mode"):
continue #added exception
continue
magnet(context, obj, fcurve)

return
Expand All @@ -103,10 +105,10 @@ def magnet(context, obj, fcurve):
return

if getattr(fcurve.group, 'name', None) == 'animaide':
return # we don't want to select keys on reference fcurves
return

blends_action = bpy.data.actions.get('animaide')
blends_curves = getattr(blends_action, 'fcurves', None)
blends_curves = utils.curve.get_fcurves_for_action(blends_action)

delta_y = get_delta(context, obj, fcurve)

Expand All @@ -116,9 +118,12 @@ def magnet(context, obj, fcurve):
factor = 1
elif scene.frame_start <= k.co.x <= scene.frame_end:
factor = 1
elif blends_curves is not None and len(blends_curves) > 0:
blends_curve = blends_curves[0]
factor = blends_curve.evaluate(k.co.x)
elif utils.curve.get_fcurve_count(blends_curves) > 0:
blends_curve = utils.curve.get_first_fcurve(blends_curves)
if blends_curve:
factor = blends_curve.evaluate(k.co.x)
else:
factor = 0
else:
factor = 0

Expand Down Expand Up @@ -162,23 +167,26 @@ def get_delta(context, obj, fcurve):
def add_blends():
"""Add a curve with 4 control pints to an action called 'animaide' that would act as a mask for anim_offset"""
action = utils.set_animaide_action()
fcurves = getattr(action, 'fcurves', None)
if len(fcurves) == 0:
fcurves = utils.curve.get_fcurves_for_action(action)
if utils.curve.get_fcurve_count(fcurves) == 0:
return utils.curve.new('Magnet', 4)
else:
return action.fcurves[0]
first = utils.curve.get_first_fcurve(fcurves)
return first if first else utils.curve.new('Magnet', 4)


def remove_mask(context):
"""Removes the fcurve and action that are been used as a mask for anim_offset"""

anim_offset = context.scene.animaide.anim_offset
blends_action = bpy.data.actions.get('animaide')
blends_curves = getattr(blends_action, 'fcurves', None)
blends_curves = utils.curve.get_fcurves_for_action(blends_action)

anim_offset.mask_in_use = False
if blends_curves is not None and len(blends_curves) > 0:
blends_curves.remove(blends_curves[0])
if blends_curves is not None and utils.curve.get_fcurve_count(blends_curves) > 0:
first = utils.curve.get_first_fcurve(blends_curves)
if first and blends_curves:
blends_curves.remove(first)
# reset_timeline_mask(context)

return
Expand All @@ -189,10 +197,12 @@ def set_blend_values(context):

scene = context.scene
blends_action = bpy.data.actions.get('animaide')
blends_curves = getattr(blends_action, 'fcurves', None)
blends_curves = utils.curve.get_fcurves_for_action(blends_action)

if blends_curves is not None:
blend_curve = blends_curves[0]
if blends_curves is not None and utils.curve.get_fcurve_count(blends_curves) > 0:
blend_curve = utils.curve.get_first_fcurve(blends_curves)
if blend_curve is None:
return
keys = blend_curve.keyframe_points

left_blend = scene.frame_preview_start
Expand Down Expand Up @@ -239,8 +249,10 @@ def add_keys(context):

for obj in selected_objects:
action = getattr(obj.animation_data, 'action', None)
fcurves = utils.curve.get_fcurves_for_action(action)
fcurves_list = utils.curve.get_fcurves_list(fcurves) if fcurves else []

for fcurve in getattr(action, 'fcurves', list()):
for fcurve in fcurves_list:

if fcurve.lock:
return
Expand Down Expand Up @@ -327,19 +339,18 @@ def poll(context):


def get_anim_offset_globals(context, obj):
"""Get global values for the anim_offset"""

anim = obj.animation_data
if anim is None:
return
if anim.action.fcurves is None:

fcurves = utils.curve.get_fcurves_for_action(anim.action)
if fcurves is None:
return

fcurves = obj.animation_data.action.fcurves

curves = {}
fcurves_list = utils.curve.get_fcurves_list(fcurves)

for fcurve_index, fcurve in fcurves.items():
for fcurve in fcurves_list:

if fcurve.lock is True:
continue
Expand All @@ -349,8 +360,6 @@ def get_anim_offset_globals(context, obj):

values = {'x': cur_frame, 'y': cur_frame_y}

curves[fcurve_index]['current_frame'] = values
curves[fcurve.data_path] = {'current_frame': values}

global_values[obj.name] = curves


111 changes: 93 additions & 18 deletions curve_tools/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
'''

import math
import random
import bpy

# from utils.key import global_values, on_current_frame, get_selected_neigbors, \
Expand Down Expand Up @@ -49,23 +50,25 @@ def add_noise(fcurve, strength=0.4, scale=1, phase=0):
def add_shear_curve():
"""Add a curve with 4 control pints to an action called 'animaide' that would act as a mask for anim_offset"""
action = utils.set_animaide_action()
fcurves = getattr(action, 'fcurves', None)
fcurves = utils.curve.get_fcurves_for_action(action)
fcurves_list = utils.curve.get_fcurves_list(fcurves) if fcurves else []
# fcurves = utils.curve.get_all_fcurves(obj)
if len(fcurves) == 0:
if len(fcurves_list) == 0:
return utils.curve.new('Shear', 2, key_interp='VECTOR')
else:
return fcurves[0]
return fcurves_list[0]


def set_shear_values(left, right):
"""Modify the position of the fcurve 4 control points that is been used as mask to anim_offset """

# scene = context.scene
action = bpy.data.actions.get('animaide')
curves = getattr(action, 'fcurves', None)
curves = utils.curve.get_fcurves_for_action(action)
curves_list = utils.curve.get_fcurves_list(curves) if curves else []

if curves is not None:
curve = curves[0]
if curves_list:
curve = curves_list[0]
keys = curve.keyframe_points

# left_blend = scene.frame_preview_start
Expand All @@ -91,7 +94,8 @@ def shear(self, direction):
else:
direction = 0
shear_action = utils.set_animaide_action()
shear_curves = getattr(shear_action, 'fcurves', None)
shear_curves = utils.curve.get_fcurves_for_action(shear_action)
shear_curves_list = utils.curve.get_fcurves_list(shear_curves) if shear_curves else []
shear_curve = add_shear_curve()
local_y = self.right_neighbor['y'] - self.left_neighbor['y']
set_shear_values(self.left_neighbor['x'], self.right_neighbor['x'])
Expand All @@ -105,7 +109,8 @@ def shear(self, direction):
k = self.fcurve.keyframe_points[index]
k.co_ui.y = self.original_keys[index]['y'] + shear_curve.evaluate(k.co.x) * factor

shear_curves.remove(shear_curve)
if shear_curves_list:
shear_curves_list[0].remove(shear_curve)


def set_min_max_values(self, context):
Expand Down Expand Up @@ -141,10 +146,15 @@ def to_execute(self, context, function, *args):
if not action:
continue

self.fcurves = action.fcurves
self.fcurves = utils.curve.get_fcurves_for_action(action)
fcurves_list = utils.curve.get_fcurves_list(self.fcurves) if self.fcurves else []

for fcurve_i in global_fcurves:
self.fcurve = self.fcurves[fcurve_i]
# Access by index - need to handle Blender 5.0 compatibility
if fcurve_i < len(fcurves_list):
self.fcurve = fcurves_list[fcurve_i]
else:
continue

self.global_fcurve = global_fcurves[fcurve_i]

Expand Down Expand Up @@ -194,8 +204,14 @@ def reset_original():
if not action:
continue

fcurves = utils.curve.get_fcurves_for_action(action)
fcurves_list = utils.curve.get_fcurves_list(fcurves) if fcurves else []

for fcurve_i in global_fcurves:
fcurve = action.fcurves[fcurve_i]
if fcurve_i < len(fcurves_list):
fcurve = fcurves_list[fcurve_i]
else:
continue

global_fcurve = global_fcurves[fcurve_i]

Expand Down Expand Up @@ -223,6 +239,58 @@ def reset_original():
return


# Function to determine if an fcurve is locked
def is_fcurve_locked(obj, fcurve):
if fcurve.lock or fcurve.mute:
return True
if not obj:
return False
print(fcurve.data_path)

# Check if the fcurve is related to a pose bone
if fcurve.data_path.startswith("pose.bones"):
bone_name = fcurve.data_path.split('"')[1] # Extract the bone name
bone = obj.pose.bones.get(bone_name)

if not bone:
return False

# Determine the specific property (location, rotation, scale)
if "location" in fcurve.data_path:
if fcurve.array_index < len(bone.lock_location):
return bone.lock_location[fcurve.array_index]
elif "rotation_quaternion" in fcurve.data_path:
if fcurve.array_index == 0:
return bone.lock_rotation_w # Quaternion W component
elif fcurve.array_index - 1 < len(bone.lock_rotation):
return bone.lock_rotation[fcurve.array_index - 1] # Quaternion X, Y, Z components
elif "rotation_euler" in fcurve.data_path:
if fcurve.array_index < len(bone.lock_rotation):
return bone.lock_rotation[fcurve.array_index] # Euler X, Y, Z components
elif "scale" in fcurve.data_path:
if fcurve.array_index < len(bone.lock_scale):
return bone.lock_scale[fcurve.array_index]
else:
# For object level properties
if fcurve.data_path.startswith("location"):
if fcurve.array_index < len(obj.lock_location):
return obj.lock_location[fcurve.array_index]
elif "rotation_quaternion" in fcurve.data_path:
if fcurve.array_index == 0:
return obj.lock_rotation_w # Quaternion W component
elif fcurve.array_index - 1 < len(obj.lock_rotation):
return obj.lock_rotation[fcurve.array_index - 1] # Quaternion X, Y, Z components
elif "rotation_euler" in fcurve.data_path:
if fcurve.array_index < len(obj.lock_rotation):
return obj.lock_rotation[fcurve.array_index] # Euler X, Y, Z components
elif fcurve.data_path.startswith("scale"):
if fcurve.array_index < len(obj.lock_scale):
return obj.lock_scale[fcurve.array_index]

return False



def get_globals(context):
"""Gets all the global values needed to work with the curve_tools"""

Expand Down Expand Up @@ -250,18 +318,27 @@ def get_globals(context):
continue

action_type = action_data['type']
fcurves = action.fcurves
fcurves = utils.curve.get_fcurves_for_action(action)
fcurves_list = utils.curve.get_fcurves_list(fcurves) if fcurves else []

if not fcurves:
if not fcurves_list:
continue

global_curve_data = {}

# Allows selection in dope sheet to work in graph editor
for fcurve_index, fcurve in fcurves.items():
fcurve.select = True
for fcurve_index, fcurve in enumerate(fcurves_list):
locked = is_fcurve_locked(obj, fcurve)
if not locked:
fcurve.select = True
else:
fcurve.select = False
for keyframe in fcurve.keyframe_points:
keyframe.select_control_point = False
keyframe.select_left_handle = False
keyframe.select_right_handle = False

for fcurve_index, fcurve in fcurves.items():
for fcurve_index, fcurve in enumerate(fcurves_list):
if not utils.curve.valid_fcurve(context, obj, fcurve, action_type=action_type):
continue

Expand Down Expand Up @@ -465,5 +542,3 @@ def linear_y(key, left_neighbor, right_neighbor):
adjacent = key.co_ui.x - left_neighbor['x']
oposite = tangent * adjacent
return left_neighbor['y'] + oposite


6 changes: 4 additions & 2 deletions key_manager/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,10 @@ def execute(self, context):
objects = context.selected_objects
for obj in objects:
action = obj.animation_data.action
fcurves = utils.curve.get_fcurves_for_action(action)
fcurves_list = utils.curve.get_fcurves_list(fcurves) if fcurves else []

for curve in action.fcurves:
for curve in fcurves_list:
if curve.select is not True:
continue
noise = curve.modifiers.new('NOISE')
Expand All @@ -398,7 +400,7 @@ def poll(cls, context):

def execute(self, context):
obj = context.object
fcurves = obj.animation_data.action.fcurves
fcurves = utils.curve.get_fcurves_for_action(obj.animation_data.action)
utils.curve.create_path(context, fcurves)


Expand Down
Loading