forked from bartvdbraak/blender
210 lines
6.3 KiB
Python
210 lines
6.3 KiB
Python
# ##### BEGIN GPL LICENSE BLOCK #####
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
# <pep8-80 compliant>
|
|
|
|
# This file defines a set of methods that are useful for various
|
|
# Relative Keying Set (RKS) related operations, such as: callbacks
|
|
# for polling, iterator callbacks, and also generate callbacks.
|
|
# All of these can be used in conjunction with the others.
|
|
|
|
__all__ = (
|
|
"path_add_property",
|
|
"RKS_POLL_selected_objects",
|
|
"RKS_POLL_selected_bones",
|
|
"RKS_POLL_selected_items",
|
|
"RKS_ITER_selected_item",
|
|
"RKS_GEN_available",
|
|
"RKS_GEN_location",
|
|
"RKS_GEN_rotation",
|
|
"RKS_GEN_scaling",
|
|
)
|
|
|
|
import bpy
|
|
|
|
###########################
|
|
# General Utilities
|
|
|
|
|
|
# Append the specified property name on the the existing path
|
|
def path_add_property(path, prop):
|
|
if path:
|
|
return path + "." + prop
|
|
else:
|
|
return prop
|
|
|
|
###########################
|
|
# Poll Callbacks
|
|
|
|
|
|
# selected objects (active object must be in object mode)
|
|
def RKS_POLL_selected_objects(ksi, context):
|
|
ob = context.active_object
|
|
if ob:
|
|
return ob.mode == 'OBJECT'
|
|
else:
|
|
return bool(context.selected_objects)
|
|
|
|
|
|
# selected bones
|
|
def RKS_POLL_selected_bones(ksi, context):
|
|
# we must be in Pose Mode, and there must be some bones selected
|
|
ob = context.active_object
|
|
if ob and ob.mode == 'POSE':
|
|
if context.active_pose_bone or context.selected_pose_bones:
|
|
return True
|
|
|
|
# nothing selected
|
|
return False
|
|
|
|
|
|
# selected bones or objects
|
|
def RKS_POLL_selected_items(ksi, context):
|
|
return (RKS_POLL_selected_bones(ksi, context) or
|
|
RKS_POLL_selected_objects(ksi, context))
|
|
|
|
###########################
|
|
# Iterator Callbacks
|
|
|
|
|
|
# all selected objects or pose bones, depending on which we've got
|
|
def RKS_ITER_selected_item(ksi, context, ks):
|
|
ob = context.active_object
|
|
if ob and ob.mode == 'POSE':
|
|
for bone in context.selected_pose_bones:
|
|
ksi.generate(context, ks, bone)
|
|
else:
|
|
for ob in context.selected_objects:
|
|
ksi.generate(context, ks, ob)
|
|
|
|
|
|
# all select objects only
|
|
def RKS_ITER_selected_objects(ksi, context, ks):
|
|
for ob in context.selected_objects:
|
|
ksi.generate(context, ks, ob)
|
|
|
|
###########################
|
|
# Generate Callbacks
|
|
|
|
|
|
# 'Available' F-Curves
|
|
def RKS_GEN_available(ksi, context, ks, data):
|
|
# try to get the animation data associated with the closest
|
|
# ID-block to the data (neither of which may exist/be easy to find)
|
|
id_block = data.id_data
|
|
adt = getattr(id_block, "animation_data", None)
|
|
|
|
# there must also be an active action...
|
|
if adt is None or adt.action is None:
|
|
return
|
|
|
|
# if we haven't got an ID-block as 'data', try to restrict
|
|
# paths added to only those which branch off from here
|
|
# i.e. for bones
|
|
if id_block != data:
|
|
basePath = data.path_from_id()
|
|
else:
|
|
basePath = None # this is not needed...
|
|
|
|
# for each F-Curve, include a path to key it
|
|
# NOTE: we don't need to set the group settings here
|
|
for fcu in adt.action.fcurves:
|
|
if basePath:
|
|
if basePath in fcu.data_path:
|
|
ks.paths.add(id_block, fcu.data_path, index=fcu.array_index)
|
|
else:
|
|
ks.paths.add(id_block, fcu.data_path, index=fcu.array_index)
|
|
|
|
# ------
|
|
|
|
|
|
# get ID block and based ID path for transform generators
|
|
# private function
|
|
def get_transform_generators_base_info(data):
|
|
# ID-block for the data
|
|
id_block = data.id_data
|
|
|
|
# get base path and grouping method/name
|
|
if isinstance(data, bpy.types.ID):
|
|
# no path in this case
|
|
path = ""
|
|
|
|
# data on ID-blocks directly should get grouped by the KeyingSet
|
|
grouping = None
|
|
else:
|
|
# get the path to the ID-block
|
|
path = data.path_from_id()
|
|
|
|
# try to use the name of the data element to group the F-Curve
|
|
# else fallback on the KeyingSet name
|
|
grouping = getattr(data, "name", None)
|
|
|
|
# return the ID-block and the path
|
|
return id_block, path, grouping
|
|
|
|
|
|
# Location
|
|
def RKS_GEN_location(ksi, context, ks, data):
|
|
# get id-block and path info
|
|
id_block, base_path, grouping = get_transform_generators_base_info(data)
|
|
|
|
# add the property name to the base path
|
|
path = path_add_property(base_path, "location")
|
|
|
|
# add Keying Set entry for this...
|
|
if grouping:
|
|
ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
|
|
else:
|
|
ks.paths.add(id_block, path)
|
|
|
|
|
|
# Rotation
|
|
def RKS_GEN_rotation(ksi, context, ks, data):
|
|
# get id-block and path info
|
|
id_block, base_path, grouping = get_transform_generators_base_info(data)
|
|
|
|
# add the property name to the base path
|
|
# rotation mode affects the property used
|
|
if data.rotation_mode == 'QUATERNION':
|
|
path = path_add_property(base_path, "rotation_quaternion")
|
|
elif data.rotation_mode == 'AXIS_ANGLE':
|
|
path = path_add_property(base_path, "rotation_axis_angle")
|
|
else:
|
|
path = path_add_property(base_path, "rotation_euler")
|
|
|
|
# add Keying Set entry for this...
|
|
if grouping:
|
|
ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
|
|
else:
|
|
ks.paths.add(id_block, path)
|
|
|
|
|
|
# Scaling
|
|
def RKS_GEN_scaling(ksi, context, ks, data):
|
|
# get id-block and path info
|
|
id_block, base_path, grouping = get_transform_generators_base_info(data)
|
|
|
|
# add the property name to the base path
|
|
path = path_add_property(base_path, "scale")
|
|
|
|
# add Keying Set entry for this...
|
|
if grouping:
|
|
ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
|
|
else:
|
|
ks.paths.add(id_block, path)
|