diff options
21 files changed, 1269 insertions, 1313 deletions
diff --git a/release/scripts/keyingsets/keyingsets_builtins.py b/release/scripts/keyingsets/keyingsets_builtins.py new file mode 100644 index 00000000000..c5417ba3d66 --- /dev/null +++ b/release/scripts/keyingsets/keyingsets_builtins.py @@ -0,0 +1,236 @@ +# Built-In Keying Sets +# None of these Keying Sets should be removed, as these +# are needed by various parts of Blender in order for them +# to work correctly. + +import bpy +from keyingsets_utils import * + +############################### +# Built-In KeyingSets + +# Location +class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo): + bl_idname = "Location" + bl_builtin = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + generate = RKS_GEN_location + +# Rotation +class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo): + bl_idname = "Rotation" + bl_builtin = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + generate = RKS_GEN_rotation + +# Scale +class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo): + bl_idname = "Scaling" + bl_builtin = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + generate = RKS_GEN_scaling + +# ------------ + +# LocRot +class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo): + bl_idname = "LocRot" + bl_builtin = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + def generate(self, context, ks, data): + # location + RKS_GEN_location(self, context, ks, data) + # rotation + RKS_GEN_rotation(self, context, ks, data) + +# LocScale +class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo): + bl_idname = "LocScale" + bl_builtin = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + def generate(self, context, ks, data): + # location + RKS_GEN_location(self, context, ks, data) + # scale + RKS_GEN_scaling(self, context, ks, data) + +# LocRotScale +class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo): + bl_idname = "LocRotScale" + bl_builtin = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + def generate(self, context, ks, data): + # location + RKS_GEN_location(self, context, ks, data) + # rotation + RKS_GEN_rotation(self, context, ks, data) + # scale + RKS_GEN_scaling(self, context, ks, data) + +# RotScale +class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo): + bl_idname = "RotScale" + bl_builtin = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + def generate(self, context, ks, data): + # rotation + RKS_GEN_rotation(self, context, ks, data) + # scaling + RKS_GEN_scaling(self, context, ks, data) + +# ------------ + +# Location +class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo): + bl_idname = "Visual Location" + bl_builtin = True + + insertkey_visual = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + generate = RKS_GEN_location + +# Rotation +class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo): + bl_idname = "Visual Rotation" + bl_builtin = True + + insertkey_visual = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + generate = RKS_GEN_rotation + +# VisualLocRot +class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo): + bl_idname = "Visual LocRot" + bl_builtin = True + + insertkey_visual = True + + # poll - use predefined callback for selected bones/objects + poll = RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + def generate(self, context, ks, data): + # location + RKS_GEN_location(self, context, ks, data) + # rotation + RKS_GEN_rotation(self, context, ks, data) + +# ------------ + +# Available +class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo): + bl_idname = "Available" + bl_builtin = True + + # poll - use predefined callback for selected objects + # TODO: this should really check whether the selected object (or datablock) + # has any animation data defined yet + poll = RKS_POLL_selected_objects + + # iterator - use callback for selected bones/objects + iterator = RKS_ITER_selected_item + + # generator - use callback for location + generate = RKS_GEN_available + +############################### + +classes = [ + BUILTIN_KSI_Location, + BUILTIN_KSI_Rotation, + BUILTIN_KSI_Scaling, + + BUILTIN_KSI_LocRot, + BUILTIN_KSI_LocScale, + BUILTIN_KSI_LocRotScale, + BUILTIN_KSI_RotScale, + + BUILTIN_KSI_VisualLoc, + BUILTIN_KSI_VisualRot, + BUILTIN_KSI_VisualLocRot, + + BUILTIN_KSI_Available, +] + + +def register(): + register = bpy.types.register + for cls in classes: + register(cls) + + +def unregister(): + unregister = bpy.types.unregister + for cls in classes: + unregister(cls) + +if __name__ == "__main__": + register() + +############################### diff --git a/release/scripts/keyingsets/keyingsets_utils.py b/release/scripts/keyingsets/keyingsets_utils.py new file mode 100644 index 00000000000..78e170c88f9 --- /dev/null +++ b/release/scripts/keyingsets/keyingsets_utils.py @@ -0,0 +1,170 @@ +# 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. + +import bpy + +########################### +# General Utilities + +# Append the specified property name on the the existing path +def path_add_property(path, prop): + if len(path): + return path + "." + prop; + else: + return prop; + +########################### +# Poll Callbacks + +# selected objects +def RKS_POLL_selected_objects(ksi, context): + return context.active_object or len(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 + if (context.active_object) and (context.active_object.mode == 'POSE'): + if context.active_pose_bone or len(context.select_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): + if (context.active_object) and (context.active_object.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) + +########################### +# 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 + try: + adt = id_block.animation_data + except: + # there isn't any animation data available + return; + + # there must also be an active action... + if adt.action is None: + return; + + # for each F-Curve, include an path to key it + # NOTE: we don't need to set the group settings here + for fcu in adt.action.fcurves: + ks.add_path(id_block, fcu.rna_path, array_index=fcu.array_index, entire_array=False) + +# ------ + +# get ID block and based ID path for transform generators +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_to_id() + + try: + # try to use the name of the data element to group the F-Curve + grouping = data.name + except: + # fallback on the KeyingSet name + grouping = 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.add_path(id_block, path, grouping_method='NAMED', group_name=grouping) + else: + ks.add_path(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 == 'AXISANGLE': + 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.add_path(id_block, path, grouping_method='NAMED', group_name=grouping) + else: + ks.add_path(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.add_path(id_block, path, grouping_method='NAMED', group_name=grouping) + else: + ks.add_path(id_block, path) + +########################### +# Un-needed stuff which is here to just shut up the warnings... + +classes = [] + +def register(): + register = bpy.types.register + for cls in classes: + register(cls) + + +def unregister(): + unregister = bpy.types.unregister + for cls in classes: + unregister(cls) + +if __name__ == "__main__": + register() + +########################### diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py index 7787d9ee5fe..5b0599fe25f 100644 --- a/release/scripts/modules/bpy/utils.py +++ b/release/scripts/modules/bpy/utils.py @@ -169,7 +169,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): _loaded[:] = [] for base_path in script_paths(user=False): - for path_subdir in ("ui", "op", "io", "cfg"): + for path_subdir in ("ui", "op", "io", "cfg", "keyingsets"): path = _os.path.join(base_path, path_subdir) if _os.path.isdir(path): sys_path_ensure(path) @@ -179,7 +179,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): user_path = user_script_path() if user_path: - for path_subdir in ("", "ui", "op", "io", "cfg"): + for path_subdir in ("", "ui", "op", "io", "cfg", "keyingsets"): path = _os.path.join(user_path, path_subdir) if _os.path.isdir(path): sys_path_ensure(path) diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index f6950ba07b8..8644074d4e9 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -71,7 +71,7 @@ void BKE_animdata_make_local(struct AnimData *adt); struct KeyingSet *BKE_keyingset_add(struct ListBase *list, const char name[], short flag, short keyingflag); /* Add a path to a KeyingSet */ -void BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode); +struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode); /* Find the destination matching the criteria given */ struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode); @@ -79,6 +79,9 @@ struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, con /* Copy all KeyingSets in the given list */ void BKE_keyingsets_copy(struct ListBase *newlist, struct ListBase *list); +/* Free the given Keying Set path */ +void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp); + /* Free data for KeyingSet but not set itself */ void BKE_keyingset_free(struct KeyingSet *ks); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index a880417a111..8ec8f24d5fe 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -621,53 +621,48 @@ KeyingSet *BKE_keyingset_add (ListBase *list, const char name[], short flag, sho return ks; } -/* Add a destination to a KeyingSet. Nothing is returned for now... +/* Add a path to a KeyingSet. Nothing is returned for now... * Checks are performed to ensure that destination is appropriate for the KeyingSet in question */ -void BKE_keyingset_add_path (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode) +KS_Path *BKE_keyingset_add_path (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode) { KS_Path *ksp; /* sanity checks */ if ELEM(NULL, ks, rna_path) { - printf("ERROR: no Keying Set and/or RNA Path to add destination with \n"); - return; + printf("ERROR: no Keying Set and/or RNA Path to add path with \n"); + return NULL; } - /* ID is optional for relative KeyingSets, but is necessary for absolute KeyingSets */ + /* ID is required for all types of KeyingSets */ if (id == NULL) { - if (ks->flag & KEYINGSET_ABSOLUTE) { - printf("ERROR: No ID provided for absolute destination. \n"); - return; - } + printf("ERROR: No ID provided for Keying Set Path. \n"); + return NULL; } /* don't add if there is already a matching KS_Path in the KeyingSet */ if (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) { if (G.f & G_DEBUG) printf("ERROR: destination already exists in Keying Set \n"); - return; + return NULL; } /* allocate a new KeyingSet Path */ ksp= MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); /* just store absolute info */ - if (ks->flag & KEYINGSET_ABSOLUTE) { - ksp->id= id; - if (group_name) - BLI_snprintf(ksp->group, 64, group_name); - else - strcpy(ksp->group, ""); - } + ksp->id= id; + if (group_name) + BLI_snprintf(ksp->group, 64, group_name); + else + strcpy(ksp->group, ""); /* store additional info for relative paths (just in case user makes the set relative) */ if (id) ksp->idtype= GS(id->name); /* just copy path info */ - // XXX no checks are performed for templates yet - // should array index be checked too? + // TODO: should array index be checked too? ksp->rna_path= BLI_strdupn(rna_path, strlen(rna_path)); ksp->array_index= array_index; @@ -677,20 +672,37 @@ void BKE_keyingset_add_path (KeyingSet *ks, ID *id, const char group_name[], con /* add KeyingSet path to KeyingSet */ BLI_addtail(&ks->paths, ksp); + + /* return this path */ + return ksp; } +/* Free the given Keying Set path */ +void BKE_keyingset_free_path (KeyingSet *ks, KS_Path *ksp) +{ + /* sanity check */ + if ELEM(NULL, ks, ksp) + return; + + /* free RNA-path info */ + MEM_freeN(ksp->rna_path); + + /* free path itself */ + BLI_freelinkN(&ks->paths, ksp); +} + /* Copy all KeyingSets in the given list */ -void BKE_keyingsets_copy(ListBase *newlist, ListBase *list) +void BKE_keyingsets_copy (ListBase *newlist, ListBase *list) { KeyingSet *ksn; KS_Path *kspn; - + BLI_duplicatelist(newlist, list); - for(ksn=newlist->first; ksn; ksn=ksn->next) { + for (ksn=newlist->first; ksn; ksn=ksn->next) { BLI_duplicatelist(&ksn->paths, &ksn->paths); - - for(kspn=ksn->paths.first; kspn; kspn=kspn->next) + + for (kspn=ksn->paths.first; kspn; kspn=kspn->next) kspn->rna_path= MEM_dupallocN(kspn->rna_path); } } @@ -709,12 +721,7 @@ void BKE_keyingset_free (KeyingSet *ks) /* free each path as we go to avoid looping twice */ for (ksp= ks->paths.first; ksp; ksp= kspn) { kspn= ksp->next; - - /* free RNA-path info */ - MEM_freeN(ksp->rna_path); - - /* free path itself */ - BLI_freelinkN(&ks->paths, ksp); + BKE_keyingset_free_path(ks, ksp); } } diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h index 5602bff77ce..379b8c27de5 100644 --- a/source/blender/editors/animation/anim_intern.h +++ b/source/blender/editors/animation/anim_intern.h @@ -33,12 +33,6 @@ /* list of builtin KeyingSets (defined in keyingsets.c) */ extern ListBase builtin_keyingsets; -/* for builtin keyingsets - context poll */ -short keyingset_context_ok_poll(bContext *C, KeyingSet *ks); - -/* Main KeyingSet operations API call */ -short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks); - /* Operator Define Prototypes ------------------- */ /* Main Keyframe Management operators: diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index d0675dc42ba..eaebab2efab 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1073,7 +1073,6 @@ static int modify_key_op_poll(bContext *C) static int insert_key_exec (bContext *C, wmOperator *op) { - ListBase dsources = {NULL, NULL}; Scene *scene= CTX_data_scene(C); KeyingSet *ks= NULL; int type= RNA_int_get(op->ptr, "type"); @@ -1098,22 +1097,17 @@ static int insert_key_exec (bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* get context info for relative Keying Sets */ - if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { - /* exit if no suitable data obtained */ - if (modifykey_get_context_data(C, &dsources, ks) == 0) { - BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set"); - return OPERATOR_CANCELLED; - } - } - /* try to insert keyframes for the channels specified by KeyingSet */ - success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + success= ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); if (G.f & G_DEBUG) BKE_reportf(op->reports, RPT_INFO, "KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success); /* report failure or do updates? */ - if (success) { + if (success == MODIFYKEY_INVALID_CONTEXT) { + BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set"); + return OPERATOR_CANCELLED; + } + else if (success) { /* if the appropriate properties have been set, make a note that we've inserted something */ if (RNA_boolean_get(op->ptr, "confirm_success")) BKE_reportf(op->reports, RPT_INFO, "Successfully added %d Keyframes for KeyingSet '%s'", success, ks->name); @@ -1123,13 +1117,6 @@ static int insert_key_exec (bContext *C, wmOperator *op) } else BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes"); - - - /* free temp context-data if available */ - if (dsources.first) { - /* we assume that there is no extra data that needs to be freed from here... */ - BLI_freelistN(&dsources); - } /* send updates */ DAG_ids_flush_update(0); @@ -1191,8 +1178,10 @@ static void insert_key_menu_prompt (bContext *C) * - these are listed in the order in which they were defined for the active scene */ if (scene->keyingsets.first) { - for (ks= scene->keyingsets.first; ks; ks= ks->next) - uiItemIntO(layout, ks->name, 0, "ANIM_OT_keyframe_insert_menu", "type", i++); + for (ks= scene->keyingsets.first; ks; ks= ks->next) { + if (ANIM_keyingset_context_ok_poll(C, ks)) + uiItemIntO(layout, ks->name, 0, "ANIM_OT_keyframe_insert_menu", "type", i++); + } uiItemS(layout); } @@ -1200,9 +1189,8 @@ static void insert_key_menu_prompt (bContext *C) i= -1; for (ks= builtin_keyingsets.first; ks; ks= ks->next) { /* only show KeyingSet if context is suitable */ - if (keyingset_context_ok_poll(C, ks)) { + if (ANIM_keyingset_context_ok_poll(C, ks)) uiItemIntO(layout, ks->name, 0, "ANIM_OT_keyframe_insert_menu", "type", i--); - } } uiPupMenuEnd(C, pup); @@ -1261,7 +1249,6 @@ void ANIM_OT_keyframe_insert_menu (wmOperatorType *ot) static int delete_key_exec (bContext *C, wmOperator *op) { - ListBase dsources = {NULL, NULL}; Scene *scene= CTX_data_scene(C); KeyingSet *ks= NULL; int type= RNA_int_get(op->ptr, "type"); @@ -1286,22 +1273,17 @@ static int delete_key_exec (bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* get context info for relative Keying Sets */ - if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { - /* exit if no suitable data obtained */ - if (modifykey_get_context_data(C, &dsources, ks) == 0) { - BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set"); - return OPERATOR_CANCELLED; - } - } - /* try to insert keyframes for the channels specified by KeyingSet */ - success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); + success= ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); if (G.f & G_DEBUG) printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success); /* report failure or do updates? */ - if (success) { + if (success == MODIFYKEY_INVALID_CONTEXT) { + BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set"); + return OPERATOR_CANCELLED; + } + else if (success) { /* if the appropriate properties have been set, make a note that we've inserted something */ if (RNA_boolean_get(op->ptr, "confirm_success")) BKE_reportf(op->reports, RPT_INFO, "Successfully removed %d Keyframes for KeyingSet '%s'", success, ks->name); @@ -1312,12 +1294,6 @@ static int delete_key_exec (bContext *C, wmOperator *op) else BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes"); - /* free temp context-data if available */ - if (dsources.first) { - /* we assume that there is no extra data that needs to be freed from here... */ - BLI_freelistN(&dsources); - } - /* send updates */ DAG_ids_flush_update(0); diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 63323a8519d..1e4180a3ae7 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -256,14 +256,8 @@ static int remove_active_ks_path_exec (bContext *C, wmOperator *op) KS_Path *ksp= BLI_findlink(&ks->paths, ks->active_path-1); if (ksp) { - /* NOTE: sync this code with BKE_keyingset_free() */ - { - /* free RNA-path info */ - MEM_freeN(ksp->rna_path); - - /* free path itself */ - BLI_freelinkN(&ks->paths, ksp); - } + /* remove the active path from the KeyingSet */ + BKE_keyingset_free_path(ks, ksp); /* the active path should now be the previously second-to-last active one */ ks->active_path--; @@ -467,663 +461,136 @@ void ANIM_OT_keyingset_button_remove (wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } -/* ************************************************** */ -/* KEYING SETS - EDITING API */ - -/* UI API --------------------------------------------- */ - -/* Build menu-string of available keying-sets (allocates memory for string) - * NOTE: mode must not be longer than 64 chars - */ -char *ANIM_build_keyingsets_menu (ListBase *list, short for_edit) -{ - DynStr *pupds= BLI_dynstr_new(); - KeyingSet *ks; - char buf[64]; - char *str; - int i; - - /* add title first */ - BLI_dynstr_append(pupds, "Keying Sets%t|"); - - /* add dummy entries for none-active */ - if (for_edit) { - BLI_dynstr_append(pupds, "Add New%x-1|"); - BLI_dynstr_append(pupds, " %x0|"); - } - else - BLI_dynstr_append(pupds, "No Keying Set%x0|"); - - /* loop through keyingsets, adding them */ - for (ks=list->first, i=1; ks; ks=ks->next, i++) { - if (for_edit == 0) - BLI_dynstr_append(pupds, "KS: "); - - BLI_dynstr_append(pupds, ks->name); - BLI_snprintf( buf, 64, "%%x%d%s", i, ((ks->next)?"|":"") ); - BLI_dynstr_append(pupds, buf); - } - - /* convert to normal MEM_malloc'd string */ - str= BLI_dynstr_get_cstring(pupds); - BLI_dynstr_free(pupds); - - return str; -} - - /* ******************************************* */ -/* KEYING SETS - BUILTIN */ - -#if 0 // XXX old keyingsets code based on adrcodes... to be restored in due course - -/* ------------- KeyingSet Defines ------------ */ -/* Note: these must all be named with the defks_* prefix, otherwise the template macro will not work! */ - -/* macro for defining keyingset contexts */ -#define KSC_TEMPLATE(ctx_name) {&defks_##ctx_name[0], NULL, sizeof(defks_##ctx_name)/sizeof(bKeyingSet)} +/* REGISTERED KEYING SETS */ -/* --- */ +/* Keying Set Type Info declarations */ +ListBase keyingset_type_infos = {NULL, NULL}; -/* check if option not available for deleting keys */ -static short incl_non_del_keys (bKeyingSet *ks, const char mode[]) -{ - /* as optimisation, assume that it is sufficient to check only first letter - * of mode (int comparison should be faster than string!) - */ - //if (strcmp(mode, "Delete")==0) - if (mode && mode[0]=='D') - return 0; - - return 1; -} +/* Built-In Keying Sets (referencing type infos)*/ +ListBase builtin_keyingsets = {NULL, NULL}; -/* Object KeyingSets ------ */ +/* --------------- */ -/* check if include shapekey entry */ -static short incl_v3d_ob_shapekey (bKeyingSet *ks, const char mode[]) +/* Find KeyingSet type info given a name */ +KeyingSetInfo *ANIM_keyingset_info_find_named (const char name[]) { - //Object *ob= (G.obedit)? (G.obedit) : (OBACT); // XXX - Object *ob= NULL; - char *newname= NULL; - - if(ob==NULL) - return 0; - - /* not available for delete mode */ - if (strcmp(mode, "Delete")==0) - return 0; + KeyingSetInfo *ksi; - /* check if is geom object that can get shapekeys */ - switch (ob->type) { - /* geometry? */ - case OB_MESH: newname= "Mesh"; break; - case OB_CURVE: newname= "Curve"; break; - case OB_SURF: newname= "Surface"; break; - case OB_LATTICE: newname= "Lattice"; break; + /* sanity checks */ + if ((name == NULL) || (name[0] == 0)) + return NULL; - /* not geometry! */ - default: - return 0; + /* search by comparing names */ + for (ksi = keyingset_type_infos.first; ksi; ksi = ksi->next) { + if (strcmp(ksi->name, name) == 0) + return ksi; } - /* if ks is shapekey entry (this could be callled for separator before too!) */ - if (ks->flag == -3) - BLI_strncpy(ks->name, newname, sizeof(ks->name)); - - /* if it gets here, it's ok */ - return 1; + /* no matches found */ + return NULL; } -/* array for object keyingset defines */ -bKeyingSet defks_v3d_object[] = -{ - /* include_cb, adrcode-getter, name, blocktype, flag, chan_num, adrcodes */ - {NULL, "Loc", ID_OB, 0, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}}, - {NULL, "Rot", ID_OB, 0, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}}, - {NULL, "Scale", ID_OB, 0, 3, {OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "LocRot", ID_OB, 0, 6, - {OB_LOC_X,OB_LOC_Y,OB_LOC_Z, - OB_ROT_X,OB_ROT_Y,OB_ROT_Z}}, - - {NULL, "LocScale", ID_OB, 0, 6, - {OB_LOC_X,OB_LOC_Y,OB_LOC_Z, - OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}}, - - {NULL, "LocRotScale", ID_OB, 0, 9, - {OB_LOC_X,OB_LOC_Y,OB_LOC_Z, - OB_ROT_X,OB_ROT_Y,OB_ROT_Z, - OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}}, - - {NULL, "RotScale", ID_OB, 0, 6, - {OB_ROT_X,OB_ROT_Y,OB_ROT_Z, - OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}}, - - {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator - - {incl_non_del_keys, "VisualLoc", ID_OB, INSERTKEY_MATRIX, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}}, - {incl_non_del_keys, "VisualRot", ID_OB, INSERTKEY_MATRIX, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}}, - - {incl_non_del_keys, "VisualLocRot", ID_OB, INSERTKEY_MATRIX, 6, - {OB_LOC_X,OB_LOC_Y,OB_LOC_Z, - OB_ROT_X,OB_ROT_Y,OB_ROT_Z}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Layer", ID_OB, 0, 1, {OB_LAY}}, // icky option... - {NULL, "Available", ID_OB, -2, 0, {0}}, - - {incl_v3d_ob_shapekey, "%l%l", 0, -1, 0, {0}}, // separator (linked to shapekey entry) - {incl_v3d_ob_shapekey, "<ShapeKey>", ID_OB, -3, 0, {0}} -}; - -/* PoseChannel KeyingSets ------ */ - -/* array for posechannel keyingset defines */ -bKeyingSet defks_v3d_pchan[] = +/* Find builtin KeyingSet by name */ +KeyingSet *ANIM_builtin_keyingset_get_named (KeyingSet *prevKS, const char name[]) { - /* include_cb, name, blocktype, flag, chan_num, adrcodes */ - {NULL, "Loc", ID_PO, 0, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}}, - {NULL, "Rot", ID_PO, COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}}, - {NULL, "Scale", ID_PO, 0, 3, {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "LocRot", ID_PO, COMMONKEY_PCHANROT, 4, - {AC_LOC_X,AC_LOC_Y,AC_LOC_Z, - KAG_CHAN_EXTEND}}, - - {NULL, "LocScale", ID_PO, 0, 6, - {AC_LOC_X,AC_LOC_Y,AC_LOC_Z, - AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}}, - - {NULL, "LocRotScale", ID_PO, COMMONKEY_PCHANROT, 7, - {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, - KAG_CHAN_EXTEND}}, - - {NULL, "RotScale", ID_PO, 0, 4, - {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, - KAG_CHAN_EXTEND}}, - - {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator - - {incl_non_del_keys, "VisualLoc", ID_PO, INSERTKEY_MATRIX, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}}, - {incl_non_del_keys, "VisualRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}}, - - {incl_non_del_keys, "VisualLocRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 4, - {AC_LOC_X,AC_LOC_Y,AC_LOC_Z, KAG_CHAN_EXTEND}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Available", ID_PO, -2, 0, {0}} -}; - -/* Material KeyingSets ------ */ - -/* array for material keyingset defines */ -bKeyingSet defks_buts_shading_mat[] = -{ - /* include_cb, name, blocktype, flag, chan_num, adrcodes */ - {NULL, "RGB", ID_MA, 0, 3, {MA_COL_R,MA_COL_G,MA_COL_B}}, - {NULL, "Alpha", ID_MA, 0, 1, {MA_ALPHA}}, - {NULL, "Halo Size", ID_MA, 0, 1, {MA_HASIZE}}, - {NULL, "Mode", ID_MA, 0, 1, {MA_MODE}}, // evil bitflags - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "All Color", ID_MA, 0, 18, - {MA_COL_R,MA_COL_G,MA_COL_B, - MA_ALPHA,MA_HASIZE, MA_MODE, - MA_SPEC_R,MA_SPEC_G,MA_SPEC_B, - MA_REF,MA_EMIT,MA_AMB,MA_SPEC,MA_HARD, - MA_MODE,MA_TRANSLU,MA_ADD}}, - - {NULL, "All Mirror", ID_MA, 0, 5, - {MA_RAYM,MA_FRESMIR,MA_FRESMIRI, - MA_FRESTRA,MA_FRESTRAI}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Ofs", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}}, - {NULL, "Size", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}}, - - {NULL, "All Mapping", ID_MA, COMMONKEY_ADDMAP, 14, - {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z, - MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z, - MAP_R,MAP_G,MAP_B,MAP_DVAR, - MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Available", ID_MA, -2, 0, {0}} -}; - -/* World KeyingSets ------ */ - -/* array for world keyingset defines */ -bKeyingSet defks_buts_shading_wo[] = -{ - /* include_cb, name, blocktype, flag, chan_num, adrcodes */ - {NULL, "Zenith RGB", ID_WO, 0, 3, {WO_ZEN_R,WO_ZEN_G,WO_ZEN_B}}, - {NULL, "Horizon RGB", ID_WO, 0, 3, {WO_HOR_R,WO_HOR_G,WO_HOR_B}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Mist", ID_WO, 0, 4, {WO_MISI,WO_MISTDI,WO_MISTSTA,WO_MISTHI}}, - {NULL, "Stars", ID_WO, 0, 5, {WO_STAR_R,WO_STAR_G,WO_STAR_B,WO_STARDIST,WO_STARSIZE}}, - - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Ofs", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}}, - {NULL, "Size", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}}, - - {NULL, "All Mapping", ID_WO, COMMONKEY_ADDMAP, 14, - {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z, - MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z, - MAP_R,MAP_G,MAP_B,MAP_DVAR, - MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Available", ID_WO, -2, 0, {0}} -}; - -/* Lamp KeyingSets ------ */ - -/* array for lamp keyingset defines */ -bKeyingSet defks_buts_shading_la[] = -{ - /* include_cb, name, blocktype, flag, chan_num, adrcodes */ - {NULL, "RGB", ID_LA, 0, 3, {LA_COL_R,LA_COL_G,LA_COL_B}}, - {NULL, "Energy", ID_LA, 0, 1, {LA_ENERGY}}, - {NULL, "Spot Size", ID_LA, 0, 1, {LA_SPOTSI}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Ofs", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}}, - {NULL, "Size", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}}, - - {NULL, "All Mapping", ID_LA, COMMONKEY_ADDMAP, 14, - {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z, - MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z, - MAP_R,MAP_G,MAP_B,MAP_DVAR, - MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}}, + KeyingSet *ks, *first=NULL; - {NULL, "%l", 0, -1, 0, {0}}, // separator + /* sanity checks any name to check? */ + if (name[0] == 0) + return NULL; - {NULL, "Available", ID_LA, -2, 0, {0}} -}; - -/* Texture KeyingSets ------ */ - -/* array for texture keyingset defines */ -bKeyingSet defks_buts_shading_tex[] = -{ - /* include_cb, name, blocktype, flag, chan_num, adrcodes */ - {NULL, "Clouds", ID_TE, 0, 5, - {TE_NSIZE,TE_NDEPTH,TE_NTYPE, - TE_MG_TYP,TE_N_BAS1}}, - - {NULL, "Marble", ID_TE, 0, 7, - {TE_NSIZE,TE_NDEPTH,TE_NTYPE, - TE_TURB,TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}}, - - {NULL, "Stucci", ID_TE, 0, 5, - {TE_NSIZE,TE_NTYPE,TE_TURB, - TE_MG_TYP,TE_N_BAS1}}, - - {NULL, "Wood", ID_TE, 0, 6, - {TE_NSIZE,TE_NTYPE,TE_TURB, - TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}}, - - {NULL, "Magic", ID_TE, 0, 2, {TE_NDEPTH,TE_TURB}}, - - {NULL, "Blend", ID_TE, 0, 1, {TE_MG_TYP}}, - - {NULL, "Musgrave", ID_TE, 0, 6, - {TE_MG_TYP,TE_MGH,TE_MG_LAC, - TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN}}, - - {NULL, "Voronoi", ID_TE, 0, 9, - {TE_VNW1,TE_VNW2,TE_VNW3,TE_VNW4, - TE_VNMEXP,TE_VN_DISTM,TE_VN_COLT, - TE_ISCA,TE_NSIZE}}, + /* get first KeyingSet to use */ + if (prevKS && prevKS->next) + first= prevKS->next; + else + first= builtin_keyingsets.first; - {NULL, "Distorted Noise", ID_TE, 0, 4, - {TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN,TE_DISTA}}, - - {NULL, "Color Filter", ID_TE, 0, 5, - {TE_COL_R,TE_COL_G,TE_COL_B,TE_BRIGHT,TE_CONTRA}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Available", ID_TE, -2, 0, {0}} -}; - -/* Object Buttons KeyingSets ------ */ - -/* check if include particles entry */ -static short incl_buts_ob (bKeyingSet *ks, const char mode[]) -{ - //Object *ob= OBACT; // xxx - Object *ob= NULL; - /* only if object is mesh type */ - - if(ob==NULL) return 0; - return (ob->type == OB_MESH); -} - -/* array for texture keyingset defines */ -bKeyingSet defks_buts_object[] = -{ - /* include_cb, name, blocktype, flag, chan_num, adrcodes */ - {incl_buts_ob, "Surface Damping", ID_OB, 0, 1, {OB_PD_SDAMP}}, - {incl_buts_ob, "Random Damping", ID_OB, 0, 1, {OB_PD_RDAMP}}, - {incl_buts_ob, "Permeability", ID_OB, 0, 1, {OB_PD_PERM}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator - - {NULL, "Force Strength", ID_OB, 0, 1, {OB_PD_FSTR}}, - {NULL, "Force Falloff", ID_OB, 0, 1, {OB_PD_FFALL}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator + /* loop over KeyingSets checking names */ + for (ks= first; ks; ks= ks->next) { + if (strcmp(name, ks->name) == 0) + return ks; + } - {NULL, "Available", ID_OB, -2, 0, {0}} // this will include ob-transforms too! -}; - -/* Camera Buttons KeyingSets ------ */ - -/* check if include internal-renderer entry */ -static short incl_buts_cam1 (bKeyingSet *ks, const char mode[]) -{ - Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first! - /* only if renderer is internal renderer */ - return (scene->r.renderer==R_INTERN); + /* no matches found */ + return NULL; } -/* check if include external-renderer entry */ -static short incl_buts_cam2 (bKeyingSet *ks, const char mode[]) -{ - Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first! - /* only if renderer is internal renderer */ - return (scene->r.renderer!=R_INTERN); -} +/* --------------- */ -/* array for camera keyingset defines */ -bKeyingSet defks_buts_cam[] = +/* Add the given KeyingSetInfo to the list of type infos, and create an appropriate builtin set too */ +void ANIM_keyingset_info_register (const bContext *C, KeyingSetInfo *ksi) { - /* include_cb, name, blocktype, flag, chan_num, adrcodes */ - {NULL, "Lens", ID_CA, 0, 1, {CAM_LENS}}, - {NULL, "Clipping", ID_CA, 0, 2, {CAM_STA,CAM_END}}, - {NULL, "Focal Distance", ID_CA, 0, 1, {CAM_YF_FDIST}}, - - {NULL, "%l", 0, -1, 0, {0}}, // separator + Scene *scene = CTX_data_scene(C); + ListBase *list = NULL; + KeyingSet *ks; + /* determine the KeyingSet list to include the new KeyingSet in */ + if (ksi->builtin) + list = &builtin_keyingsets; + else + list = &scene->keyingsets; - {incl_buts_cam2, "Aperture", ID_CA, 0, 1, {CAM_YF_APERT}}, - {incl_buts_cam1, "Viewplane Shift", ID_CA, 0, 2, {CAM_SHIFT_X,CAM_SHIFT_Y}}, + /* create a new KeyingSet + * - inherit name and keyframing settings from the typeinfo + */ + ks = BKE_keyingset_add(list, ksi->name, ksi->builtin, ksi->keyingflag); - {NULL, "%l", 0, -1, 0, {0}}, // separator + /* link this KeyingSet with its typeinfo */ + memcpy(&ks->typeinfo, ksi->name, sizeof(ks->typeinfo)); - {NULL, "Available", ID_CA, -2, 0, {0}} -}; - -/* --- */ + /* add type-info to the list */ + BLI_addtail(&keyingset_type_infos, ksi); +} -/* Keying Context Defines - Must keep in sync with enumeration (eKS_Contexts) */ -bKeyingContext ks_contexts[] = +/* Remove the given KeyingSetInfo from the list of type infos, and also remove the builtin set if appropriate */ +void ANIM_keyingset_info_unregister (const bContext *C, KeyingSetInfo *ksi) { - KSC_TEMPLATE(v3d_object), - KSC_TEMPLATE(v3d_pchan), + Scene *scene = CTX_data_scene(C); + KeyingSet *ks, *ksn; - KSC_TEMPLATE(buts_shading_mat), - KSC_TEMPLATE(buts_shading_wo), - KSC_TEMPLATE(buts_shading_la), - KSC_TEMPLATE(buts_shading_tex), - - KSC_TEMPLATE(buts_object), - KSC_TEMPLATE(buts_cam) -}; - -/* Keying Context Enumeration - Must keep in sync with definitions*/ -typedef enum eKS_Contexts { - KSC_V3D_OBJECT = 0, - KSC_V3D_PCHAN, - - KSC_BUTS_MAT, - KSC_BUTS_WO, - KSC_BUTS_LA, - KSC_BUTS_TEX, - - KSC_BUTS_OB, - KSC_BUTS_CAM, - - /* make sure this last one remains untouched! */ - KSC_TOT_TYPES -} eKS_Contexts; - - -#endif // XXX old keyingsets code based on adrcodes... to be restored in due course - -/* Macros for Declaring KeyingSets ------------------- */ - -/* A note about this system for declaring built-in Keying Sets: - * One may ask, "What is the purpose of all of these macros and static arrays?" and - * "Why not call the KeyingSets API defined in BKE_animsys.h?". The answer is two-fold. - * - * 1) Firstly, we use static arrays of struct definitions instead of function calls, as - * it reduces the start-up overhead and allocated-memory footprint of Blender. If we called - * the KeyingSets API to build these sets, the overhead of checking for unique names, allocating - * memory for each and every path and KeyingSet, scattered around in RAM, all of which would increase - * the startup time (which is totally unacceptable) and could lead to fragmentation+slower access times. - * 2) Since we aren't using function calls, we need a nice way of defining these KeyingSets in a way which - * is easily readable and less prone to breakage from changes to the underlying struct definitions. Further, - * adding additional entries SHOULD NOT require custom code to be written to access these new entries/sets. - * Therefore, here we have a system with nice, human-readable statements via macros, and static arrays which - * are linked together using more special macros + struct definitions, allowing for such a generic + simple - * initialisation function (init_builtin_keyingsets()) compared with that of something like the Nodes system. - * - * -- Joshua Leung, April 2009 - */ - -/* Struct type for declaring builtin KeyingSets in as entries in static arrays*/ -typedef struct bBuiltinKeyingSet { - KeyingSet ks; /* the KeyingSet to build */ - int tot; /* the total number of paths defined */ - KS_Path paths[64]; /* the paths for the KeyingSet to use */ -} bBuiltinKeyingSet; - - /* WARNING: the following macros must be kept in sync with the - * struct definitions in DNA_anim_types.h! - */ - -/* macro for defining a builtin KeyingSet */ -#define BI_KS_DEFINE_BEGIN(name, keyingflag) \ - {{NULL, NULL, {NULL, NULL}, name, KEYINGSET_BUILTIN, keyingflag}, - -/* macro to finish defining a builtin KeyingSet */ -#define BI_KS_DEFINE_END \ - } - -/* macro to start defining paths for a builtin KeyingSet */ -#define BI_KS_PATHS_BEGIN(tot) \ - tot, { - -/* macro to finish defining paths for a builtin KeyingSet */ -#define BI_KS_PATHS_END \ + /* find relevant scene KeyingSets which use this, and remove them */ + for (ks= scene->keyingsets.first; ks; ks= ksn) { + ksn = ks->next; + + /* remove if matching typeinfo name */ + if (strcmp(ks->typeinfo, ksi->name) == 0) { + BKE_keyingset_free(ks); + BLI_freelinkN(&scene->keyingsets, ks); + } } -/* macro for defining a builtin KeyingSet's path */ -#define BI_KSP_DEFINE(id_type, templates, prop_path, array_index, flag, groupflag) \ - {NULL, NULL, NULL, "", id_type, templates, prop_path, array_index, flag, groupflag} + /* do the same with builtin sets? */ + // TODO: this isn't done now, since unregister is really only used atm when we + // reload the scripts, which kindof defeats the purpose of "builtin"? -/* macro for defining a builtin KeyingSet with no paths (use in place of BI_KS_PAHTS_BEGIN/END block) */ -#define BI_KS_PATHS_NONE \ - 0, {0} -/* ---- */ - -/* Struct type for finding all the arrays of builtin KeyingSets */ -typedef struct bBuiltinKSContext { - bBuiltinKeyingSet *bks; /* array of KeyingSet definitions */ - int tot; /* number of KeyingSets in this array */ -} bBuiltinKSContext; - -/* macro for defining builtin KeyingSet sets - * NOTE: all the arrays of sets must follow this naming convention! - */ -#define BKSC_TEMPLATE(ctx_name) {&def_builtin_keyingsets_##ctx_name[0], sizeof(def_builtin_keyingsets_##ctx_name)/sizeof(bBuiltinKeyingSet)} - - -/* 3D-View Builtin KeyingSets ------------------------ */ - -static bBuiltinKeyingSet def_builtin_keyingsets_v3d[] = -{ - /* Simple Keying Sets ************************************* */ - /* Keying Set - "Location" ---------- */ - BI_KS_DEFINE_BEGIN("Location", 0) - BI_KS_PATHS_BEGIN(1) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END, - - /* Keying Set - "Rotation" ---------- */ - BI_KS_DEFINE_BEGIN("Rotation", 0) - BI_KS_PATHS_BEGIN(1) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END, - - /* Keying Set - "Scaling" ---------- */ - BI_KS_DEFINE_BEGIN("Scaling", 0) - BI_KS_PATHS_BEGIN(1) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "scale", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END, - - /* Compound Keying Sets *********************************** */ - /* Keying Set - "LocRot" ---------- */ - BI_KS_DEFINE_BEGIN("LocRot", 0) - BI_KS_PATHS_BEGIN(2) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END, - - /* Keying Set - "LocRotScale" ---------- */ - BI_KS_DEFINE_BEGIN("LocRotScale", 0) - BI_KS_PATHS_BEGIN(3) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "scale", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END, - - /* Keying Sets with Keying Flags ************************* */ - /* Keying Set - "VisualLoc" ---------- */ - BI_KS_DEFINE_BEGIN("VisualLoc", INSERTKEY_MATRIX) - BI_KS_PATHS_BEGIN(1) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END, - - /* Keying Set - "Rotation" ---------- */ - BI_KS_DEFINE_BEGIN("VisualRot", INSERTKEY_MATRIX) - BI_KS_PATHS_BEGIN(1) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END, - - /* Keying Set - "VisualLocRot" ---------- */ - BI_KS_DEFINE_BEGIN("VisualLocRot", INSERTKEY_MATRIX) - BI_KS_PATHS_BEGIN(2) - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), - BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) - BI_KS_PATHS_END - BI_KS_DEFINE_END -}; - -/* All Builtin KeyingSets ------------------------ */ - -/* total number of builtin KeyingSet contexts */ -#define MAX_BKSC_TYPES 1 - -/* array containing all the available builtin KeyingSets definition sets - * - size of this is MAX_BKSC_TYPES+1 so that we don't smash the stack - */ -static bBuiltinKSContext def_builtin_keyingsets[MAX_BKSC_TYPES+1] = -{ - BKSC_TEMPLATE(v3d) - /* add more contexts above this line... */ -}; - - -/* ListBase of these KeyingSets chained up ready for usage - * NOTE: this is exported to keyframing.c for use... - */ -ListBase builtin_keyingsets = {NULL, NULL}; - -/* Utility API ------------------------ */ - -/* Link up all of the builtin Keying Sets when starting up Blender - * This is called from WM_init() in wm_init_exit.c - */ -void init_builtin_keyingsets (void) -{ - bBuiltinKSContext *bksc; - bBuiltinKeyingSet *bks; - int bksc_i, bks_i; - - /* loop over all the sets of KeyingSets, setting them up, and chaining them to the builtins list */ - for (bksc_i= 0, bksc= &def_builtin_keyingsets[0]; bksc_i < MAX_BKSC_TYPES; bksc_i++, bksc++) - { - /* for each set definitions for a builtin KeyingSet, chain the paths to that KeyingSet and add */ - for (bks_i= 0, bks= bksc->bks; bks_i < bksc->tot; bks_i++, bks++) - { - KeyingSet *ks= &bks->ks; - KS_Path *ksp; - int pIndex; - - /* loop over paths, linking them to the KeyingSet and each other */ - for (pIndex= 0, ksp= &bks->paths[0]; pIndex < bks->tot; pIndex++, ksp++) - BLI_addtail(&ks->paths, ksp); - - /* add KeyingSet to builtin sets list */ - BLI_addtail(&builtin_keyingsets, ks); - } - } + /* free the type info */ + BLI_freelinkN(&keyingset_type_infos, ksi); } +/* --------------- */ -/* Get the first builtin KeyingSet with the given name, which occurs after the given one (or start of list if none given) */ -KeyingSet *ANIM_builtin_keyingset_get_named (KeyingSet *prevKS, char name[]) +void ANIM_keyingset_infos_exit () { - KeyingSet *ks, *first=NULL; - - /* sanity checks - any name to check? */ - if (name[0] == 0) - return NULL; + KeyingSetInfo *ksi, *next; - /* get first KeyingSet to use */ - if (prevKS && prevKS->next) - first= prevKS->next; - else - first= builtin_keyingsets.first; + /* free type infos */ + for (ksi=keyingset_type_infos.first; ksi; ksi=next) { + next= ksi->next; - /* loop over KeyingSets checking names */ - for (ks= first; ks; ks= ks->next) { - if (strcmp(name, ks->name) == 0) - return ks; + /* free extra RNA data, and remove from list */ + if (ksi->ext.free) + ksi->ext.free(ksi->ext.data); + BLI_freelinkN(&keyingset_type_infos, ksi); } - /* no matches found */ - return NULL; + /* free builtin sets */ + BKE_keyingsets_free(&builtin_keyingsets); } +/* ******************************************* */ +/* KEYING SETS API (for UI) */ /* Get the active Keying Set for the Scene provided */ KeyingSet *ANIM_scene_get_active_keyingset (Scene *scene) @@ -1142,127 +609,74 @@ KeyingSet *ANIM_scene_get_active_keyingset (Scene *scene) return NULL; } -/* ******************************************* */ -/* KEYFRAME MODIFICATION */ - -/* KeyingSet Menu Helpers ------------ */ - -/* Extract the maximum set of requirements from the KeyingSet */ -static int keyingset_relative_get_templates (KeyingSet *ks) +/* Check if KeyingSet can be used in the current context */ +short ANIM_keyingset_context_ok_poll (bContext *C, KeyingSet *ks) { - KS_Path *ksp; - int templates= 0; - - /* loop over the paths (could be slow to do for a number of KeyingSets)? */ - for (ksp= ks->paths.first; ksp; ksp= ksp->next) { - /* add the destination's templates to the set of templates required for the set */ - templates |= ksp->templates; + if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { + KeyingSetInfo *ksi = ANIM_keyingset_info_find_named(ks->typeinfo); + + /* get the associated 'type info' for this KeyingSet */ + if (ksi == NULL) + return 0; + // TODO: check for missing callbacks! + + /* check if it can be used in the current context */ + return (ksi->poll(ksi, C)); } - return templates; -} - -/* Check if context data is suitable for the given Keying Set */ -short keyingset_context_ok_poll (bContext *C, KeyingSet *ks) -{ - // TODO: - // For 'relative' keyingsets (i.e. py-keyingsets), add a call here - // which basically gets a listing of all the paths to be used for this - // set. - - return 1; } -/* KeyingSet Context Operations ------------ */ +/* ******************************************* */ +/* KEYFRAME MODIFICATION */ + +/* Special 'Overrides' Iterator for Relative KeyingSets ------ */ + +/* 'Data Sources' for relative Keying Set 'overrides' + * - this is basically a wrapper for PointerRNA's in a linked list + * - do not allow this to be accessed from outside for now + */ +typedef struct tRKS_DSource { + struct tRKS_DSource *next, *prev; + PointerRNA ptr; /* the whole point of this exercise! */ +} tRKS_DSource; + -/* Get list of data-sources from context (in 3D-View) for inserting keyframes using the given relative Keying Set */ -static short modifykey_get_context_v3d_data (bContext *C, ListBase *dsources, KeyingSet *ks) +/* Iterator used for overriding the behaviour of iterators defined for + * relative Keying Sets, with the main usage of this being operators + * requiring Auto Keyframing. Internal Use Only! + */ +static void RKS_ITER_overrides_list (KeyingSetInfo *ksi, bContext *C, KeyingSet *ks, ListBase *dsources) { - bCommonKeySrc *cks; - Object *obact= CTX_data_active_object(C); - int templates; - short ok= 0; - - /* get the templates in use in this KeyingSet which we should supply data for */ - templates = keyingset_relative_get_templates(ks); - - /* check if the active object is in PoseMode (i.e. only deal with bones) */ - // TODO: check with the templates to see what we really need to store - if ((obact && obact->pose) && (obact->mode & OB_MODE_POSE)) { - /* Pose Mode: Selected bones */ -#if 0 - //set_pose_keys(ob); /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */ - - /* loop through posechannels */ - //for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { - // if (pchan->flag & POSE_KEY) { - // } - //} -#endif - - CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) - { - /* add a new keying-source */ - cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc"); - BLI_addtail(dsources, cks); - - /* set necessary info */ - cks->id= &obact->id; - cks->pchan= pchan; - - if (templates & KSP_TEMPLATE_CONSTRAINT) - cks->con= constraints_get_active(&pchan->constraints); - - ok= 1; - } - CTX_DATA_END; - } - else { - /* Object Mode: Selected objects */ - CTX_DATA_BEGIN(C, Object*, ob, selected_objects) - { - /* add a new keying-source */ - cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc"); - BLI_addtail(dsources, cks); - - /* set necessary info */ - cks->id= &ob->id; - - if (templates & KSP_TEMPLATE_CONSTRAINT) - cks->con= constraints_get_active(&ob->constraints); - - ok= 1; - } - CTX_DATA_END; - } + tRKS_DSource *ds; - /* return whether any data was extracted */ - return ok; + for (ds = dsources->first; ds; ds = ds->next) { + /* run generate callback on this data */ + ksi->generate(ksi, C, ks, &ds->ptr); + } } -/* Get list of data-sources from context for inserting keyframes using the given relative Keying Set */ -short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks) +/* Add new data source for relative Keying Sets */ +void ANIM_relative_keyingset_add_source (ListBase *dsources, ID *id, StructRNA *srna, void *data) { - ScrArea *sa= CTX_wm_area(C); + tRKS_DSource *ds; - /* for now, the active area is used to determine what set of contexts apply */ - if (sa == NULL) - return 0; + /* sanity checks + * we must have at least one valid data pointer to use + */ + if (ELEM(NULL, dsources, srna) || ((id == data) && (id == NULL))) + return; -#if 0 - switch (sa->spacetype) { - case SPACE_VIEW3D: /* 3D-View: Selected Objects or Bones */ - return modifykey_get_context_v3d_data(C, dsources, ks); - } + /* allocate new elem, and add to the list */ + ds = MEM_callocN(sizeof(tRKS_DSource), "tRKS_DSource"); + BLI_addtail(dsources, ds); - /* nothing happened */ - return 0; -#endif - - /* looking into this code, it doesnt use the 3D view - Campbell */ - return modifykey_get_context_v3d_data(C, dsources, ks); -} + /* depending on what data we have, create using ID or full pointer call */ + if (srna && data) + RNA_pointer_create(id, srna, data, &ds->ptr); + else + RNA_id_pointer_create(id, &ds->ptr); +} /* KeyingSet Operations (Insert/Delete Keyframes) ------------ */ @@ -1270,8 +684,9 @@ short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets. * Returns the number of channels that keyframes were added to */ -int modify_keyframes (Scene *scene, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) +int ANIM_apply_keyingset (bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) { + Scene *scene= CTX_data_scene(C); KS_Path *ksp; int kflag=0, success= 0; char *groupname= NULL; @@ -1291,201 +706,101 @@ int modify_keyframes (Scene *scene, ListBase *dsources, bAction *act, KeyingSet else if (mode == MODIFYKEY_MODE_DELETE) kflag= 0; - /* check if the KeyingSet is absolute or not (i.e. does it requires sources info) */ - if (ks->flag & KEYINGSET_ABSOLUTE) { - /* Absolute KeyingSets are simpler to use, as all the destination info has already been - * provided by the user, and is stored, ready to use, in the KeyingSet paths. + /* if relative Keying Sets, poll and build up the paths */ + if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { + KeyingSetInfo *ksi = ANIM_keyingset_info_find_named(ks->typeinfo); + + /* clear all existing paths + * NOTE: BKE_keyingset_free() frees all of the paths for the KeyingSet, but not the set itself */ - for (ksp= ks->paths.first; ksp; ksp= ksp->next) { - int arraylen, i; - - /* get pointer to name of group to add channels to */ - if (ksp->groupmode == KSP_GROUP_NONE) - groupname= NULL; - else if (ksp->groupmode == KSP_GROUP_KSNAME) - groupname= ks->name; - else - groupname= ksp->group; - - /* init arraylen and i - arraylen should be greater than i so that - * normal non-array entries get keyframed correctly - */ - i= ksp->array_index; - arraylen= i; - - /* get length of array if whole array option is enabled */ - if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - - RNA_id_pointer_create(ksp->id, &id_ptr); - if (RNA_path_resolve(&id_ptr, ksp->rna_path, &ptr, &prop) && prop) - arraylen= RNA_property_array_length(&ptr, prop); - } - - /* we should do at least one step */ - if (arraylen == i) - arraylen++; - - /* for each possible index, perform operation - * - assume that arraylen is greater than index + BKE_keyingset_free(ks); + + /* get the associated 'type info' for this KeyingSet */ + if (ksi == NULL) + return MODIFYKEY_MISSING_TYPEINFO; + // TODO: check for missing callbacks! + + /* check if it can be used in the current context */ + if (ksi->poll(ksi, C)) { + /* if a list of data sources are provided, run a special iterator over them, + * otherwise, just continue per normal */ - for (; i < arraylen; i++) { - /* action to take depends on mode */ - if (mode == MODIFYKEY_MODE_INSERT) - success += insert_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag); - else if (mode == MODIFYKEY_MODE_DELETE) - success += delete_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag); - } - - /* set recalc-flags */ - if (ksp->id) { - switch (GS(ksp->id->name)) { - case ID_OB: /* Object (or Object-Related) Keyframes */ - { - Object *ob= (Object *)ksp->id; - - ob->recalc |= OB_RECALC; - } - break; - } + if (dsources) + RKS_ITER_overrides_list(ksi, C, ks, dsources); + else + ksi->iter(ksi, C, ks); - /* send notifiers for updates (this doesn't require context to work!) */ - WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); - } + /* if we don't have any paths now, then this still qualifies as invalid context */ + if (ks->paths.first == NULL) + return MODIFYKEY_INVALID_CONTEXT; + } + else { + /* poll callback tells us that KeyingSet is useless in current context */ + return MODIFYKEY_INVALID_CONTEXT; } } - else if (dsources && dsources->first) { - /* for each one of the 'sources', resolve the template markers and expand arrays, then insert keyframes */ - bCommonKeySrc *cks; + + /* apply the paths as specified in the KeyingSet now */ + for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + int arraylen, i; + short kflag2; - /* for each 'source' for keyframe data, resolve each of the paths from the KeyingSet */ - for (cks= dsources->first; cks; cks= cks->next) { - /* for each path in KeyingSet, construct a path using the templates */ - for (ksp= ks->paths.first; ksp; ksp= ksp->next) { - DynStr *pathds= BLI_dynstr_new(); - char *path = NULL; - int arraylen, i; - - /* set initial group name */ - if (cks->id == NULL) { - printf("ERROR: Skipping 'Common-Key' Source. No valid ID present.\n"); - continue; - } - else - groupname= cks->id->name+2; - - /* construct the path */ - // FIXME: this currently only works with a few hardcoded cases - if ((ksp->templates & KSP_TEMPLATE_PCHAN) && (cks->pchan)) { - /* add basic pose-channel path access */ - BLI_dynstr_append(pathds, "pose.bones[\""); - BLI_dynstr_append(pathds, cks->pchan->name); - BLI_dynstr_append(pathds, "\"]"); - - /* override default group name */ - groupname= cks->pchan->name; - } - if ((ksp->templates & KSP_TEMPLATE_CONSTRAINT) && (cks->con)) { - /* add basic constraint path access */ - BLI_dynstr_append(pathds, "constraints[\""); - BLI_dynstr_append(pathds, cks->con->name); - BLI_dynstr_append(pathds, "\"]"); - - /* override default group name */ - groupname= cks->con->name; - } + /* since keying settings can be defined on the paths too, extend the path before using it */ + kflag2 = (kflag | ksp->keyingflag); + + /* get pointer to name of group to add channels to */ + if (ksp->groupmode == KSP_GROUP_NONE) + groupname= NULL; + else if (ksp->groupmode == KSP_GROUP_KSNAME) + groupname= ks->name; + else + groupname= ksp->group; + + /* init arraylen and i - arraylen should be greater than i so that + * normal non-array entries get keyframed correctly + */ + i= ksp->array_index; + arraylen= i; + + /* get length of array if whole array option is enabled */ + if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) { + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + + RNA_id_pointer_create(ksp->id, &id_ptr); + if (RNA_path_resolve(&id_ptr, ksp->rna_path, &ptr, &prop) && prop) + arraylen= RNA_property_array_length(&ptr, prop); + } + + /* we should do at least one step */ + if (arraylen == i) + arraylen++; + + /* for each possible index, perform operation + * - assume that arraylen is greater than index + */ + for (; i < arraylen; i++) { + /* action to take depends on mode */ + if (mode == MODIFYKEY_MODE_INSERT) + success += insert_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); + else if (mode == MODIFYKEY_MODE_DELETE) + success += delete_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); + } + + /* set recalc-flags */ + if (ksp->id) { + switch (GS(ksp->id->name)) { + case ID_OB: /* Object (or Object-Related) Keyframes */ { - /* add property stored in KeyingSet Path */ - if (BLI_dynstr_get_len(pathds)) - BLI_dynstr_append(pathds, "."); - - /* apply some further templates? */ - if (ksp->templates & KSP_TEMPLATE_ROT) { - /* for builtin Keying Sets, this template makes the best fitting path for the - * current rotation mode of the Object / PoseChannel to be used - */ - if (strcmp(ksp->rna_path, "rotation")==0) { - /* get rotation mode */ - short rotmode= (cks->pchan)? (cks->pchan->rotmode) : - (GS(cks->id->name)==ID_OB)? ( ((Object *)cks->id)->rotmode ) : - (0); - - /* determine path to build */ - if (rotmode == ROT_MODE_QUAT) - BLI_dynstr_append(pathds, "rotation_quaternion"); - else if (rotmode == ROT_MODE_AXISANGLE) - BLI_dynstr_append(pathds, "rotation_axis_angle"); - else - BLI_dynstr_append(pathds, "rotation_euler"); - } - } - else { - /* just directly use the path */ - BLI_dynstr_append(pathds, ksp->rna_path); - } - - /* convert to C-string */ - path= BLI_dynstr_get_cstring(pathds); - BLI_dynstr_free(pathds); - } - - /* get pointer to name of group to add channels to - * - KSP_GROUP_TEMPLATE_ITEM is handled above while constructing the paths - */ - if (ksp->groupmode == KSP_GROUP_NONE) - groupname= NULL; - else if (ksp->groupmode == KSP_GROUP_KSNAME) - groupname= ks->name; - else if (ksp->groupmode == KSP_GROUP_NAMED) - groupname= ksp->group; - - /* init arraylen and i - arraylen should be greater than i so that - * normal non-array entries get keyframed correctly - */ - i= ksp->array_index; - arraylen= i+1; - - /* get length of array if whole array option is enabled */ - if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; + Object *ob= (Object *)ksp->id; - RNA_id_pointer_create(cks->id, &id_ptr); - if (RNA_path_resolve(&id_ptr, path, &ptr, &prop) && prop) - arraylen= RNA_property_array_length(&ptr, prop); - } - - /* for each possible index, perform operation - * - assume that arraylen is greater than index - */ - for (; i < arraylen; i++) { - /* action to take depends on mode */ - if (mode == MODIFYKEY_MODE_INSERT) - success+= insert_keyframe(cks->id, act, groupname, path, i, cfra, kflag); - else if (mode == MODIFYKEY_MODE_DELETE) - success+= delete_keyframe(cks->id, act, groupname, path, i, cfra, kflag); + ob->recalc |= OB_RECALC; } - - /* free the path */ - MEM_freeN(path); + break; } - /* set recalc-flags */ - if (cks->id) { - switch (GS(cks->id->name)) { - case ID_OB: /* Object (or Object-Related) Keyframes */ - { - Object *ob= (Object *)cks->id; - - ob->recalc |= OB_RECALC; - } - break; - } - - /* send notifiers for updates (this doesn't require context to work!) */ - WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); - } + /* send notifiers for updates (this doesn't require context to work!) */ + WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); } } diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 4a3ef38daa6..3f26a146c53 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -4867,12 +4867,7 @@ static int pose_clear_scale_exec(bContext *C, wmOperator *op) Object *ob= CTX_data_active_object(C); KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scaling"); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; + short autokey = 0; /* only clear those channels that are not locked */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) { @@ -4885,13 +4880,12 @@ static int pose_clear_scale_exec(bContext *C, wmOperator *op) /* do auto-keyframing as appropriate */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - /* clear any unkeyed tags */ if (pchan->bone) pchan->bone->flag &= ~BONE_UNKEYED; + + /* tag for autokeying later */ + autokey = 1; } else { /* add unkeyed tags */ @@ -4901,6 +4895,16 @@ static int pose_clear_scale_exec(bContext *C, wmOperator *op) } CTX_DATA_END; + /* perform autokeying on the bones if needed */ + if (autokey) { + /* insert keyframes */ + ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + + /* now recalculate paths */ + if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) + ED_pose_recalculate_paths(C, scene, ob); + } + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); /* note, notifier might evolve */ @@ -4930,12 +4934,7 @@ static int pose_clear_loc_exec(bContext *C, wmOperator *op) Object *ob= CTX_data_active_object(C); KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location"); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; + short autokey = 0; /* only clear those channels that are not locked */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) { @@ -4949,13 +4948,12 @@ static int pose_clear_loc_exec(bContext *C, wmOperator *op) /* do auto-keyframing as appropriate */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - /* clear any unkeyed tags */ if (pchan->bone) pchan->bone->flag &= ~BONE_UNKEYED; + + /* tag for autokeying later */ + autokey = 1; } else { /* add unkeyed tags */ @@ -4965,6 +4963,16 @@ static int pose_clear_loc_exec(bContext *C, wmOperator *op) } CTX_DATA_END; + /* perform autokeying on the bones if needed */ + if (autokey) { + /* insert keyframes */ + ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + + /* now recalculate paths */ + if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) + ED_pose_recalculate_paths(C, scene, ob); + } + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); /* note, notifier might evolve */ @@ -4994,12 +5002,7 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op) Object *ob= CTX_data_active_object(C); KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; + short autokey = 0; /* only clear those channels that are not locked */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) { @@ -5097,13 +5100,12 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op) /* do auto-keyframing as appropriate */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - /* clear any unkeyed tags */ if (pchan->bone) pchan->bone->flag &= ~BONE_UNKEYED; + + /* tag for autokeying later */ + autokey = 1; } else { /* add unkeyed tags */ @@ -5113,6 +5115,16 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op) } CTX_DATA_END; + /* perform autokeying on the bones if needed */ + if (autokey) { + /* insert keyframes */ + ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + + /* now recalculate paths */ + if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) + ED_pose_recalculate_paths(C, scene, ob); + } + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); /* note, notifier might evolve */ diff --git a/source/blender/editors/armature/poseUtils.c b/source/blender/editors/armature/poseUtils.c index e2fc2bd4088..ecc84aaf4bb 100644 --- a/source/blender/editors/armature/poseUtils.c +++ b/source/blender/editors/armature/poseUtils.c @@ -229,27 +229,28 @@ void poseAnim_mapping_autoKeyframe (bContext *C, Scene *scene, Object *ob, ListB /* insert keyframes as necessary if autokeyframing */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; tPChanFCurveLink *pfl; - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; - /* iterate over each pose-channel affected, applying the changes */ for (pfl= pfLinks->first; pfl; pfl= pfl->next) { + ListBase dsources = {NULL, NULL}; bPoseChannel *pchan= pfl->pchan; - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - /* insert keyframes */ + /* add datasource override for the PoseChannel so KeyingSet will do right thing */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); + + /* insert keyframes + * - these keyingsets here use dsources, since we need to specify exactly which keyframes get affected + */ if (pchan->flag & POSE_LOC) - modify_keyframes(scene, &dsources, NULL, ks_loc, MODIFYKEY_MODE_INSERT, cframe); + ANIM_apply_keyingset(C, &dsources, NULL, ks_loc, MODIFYKEY_MODE_INSERT, cframe); if (pchan->flag & POSE_ROT) - modify_keyframes(scene, &dsources, NULL, ks_rot, MODIFYKEY_MODE_INSERT, cframe); + ANIM_apply_keyingset(C, &dsources, NULL, ks_rot, MODIFYKEY_MODE_INSERT, cframe); if (pchan->flag & POSE_SIZE) - modify_keyframes(scene, &dsources, NULL, ks_scale, MODIFYKEY_MODE_INSERT, cframe); + ANIM_apply_keyingset(C, &dsources, NULL, ks_scale, MODIFYKEY_MODE_INSERT, cframe); + + /* free the temp info */ + BLI_freelistN(&dsources); } } } diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index 02194035ee9..8d38d0530ce 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -331,19 +331,14 @@ static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt) static int poselib_add_exec (bContext *C, wmOperator *op) { - Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); bAction *act = poselib_validate(ob); bArmature *arm= (ob) ? ob->data : NULL; bPose *pose= (ob) ? ob->pose : NULL; - bPoseChannel *pchan; TimeMarker *marker; int frame= RNA_int_get(op->ptr, "frame"); char name[64]; - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - /* sanity check (invoke should have checked this anyway) */ if (ELEM3(NULL, ob, arm, pose)) return OPERATOR_CANCELLED; @@ -373,25 +368,12 @@ static int poselib_add_exec (bContext *C, wmOperator *op) /* validate name */ BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name)); - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; - - /* loop through selected posechannels, keying their pose to the action */ - for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { - /* check if available */ - if ((pchan->bone) && (arm->layer & pchan->bone->layer)) { - if (pchan->bone->flag & BONE_SELECTED || pchan->bone==arm->act_bone) { - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - - /* KeyingSet to use depends on rotation mode (but that's handled by the templates code) */ - if (poselib_ks_locrotscale == NULL) - poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - modify_keyframes(scene, &dsources, act, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)frame); - } - } - } + /* KeyingSet to use depends on rotation mode (but that's handled by the templates code) */ + if (poselib_ks_locrotscale == NULL) + poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); + + /* make the keyingset use context info to determine where to add keyframes */ + ANIM_apply_keyingset(C, NULL, act, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)frame); /* store new 'active' pose number */ act->active_marker= BLI_countlist(&act->markers); @@ -784,13 +766,6 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData bAction *act= pld->act; bActionGroup *agrp; - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &pld->ob->id; - /* start tagging/keying */ for (agrp= act->groups.first; agrp; agrp= agrp->next) { /* only for selected action channels */ @@ -798,21 +773,23 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData pchan= get_pose_channel(pose, agrp->name); if (pchan) { - // TODO: use a standard autokeying function in future (to allow autokeying-editkeys to work) - if (IS_AUTOKEY_MODE(scene, NORMAL)) { - /* Set keys on pose - * - KeyingSet to use depends on rotation mode - * (but that's handled by the templates code) - */ + if (autokeyframe_cfra_can_key(scene, &pld->ob->id)) { + ListBase dsources = {NULL, NULL}; + + /* get KeyingSet to use */ // TODO: for getting the KeyingSet used, we should really check which channels were affected + // TODO: this should get modified so that custom props are taken into account too! if (poselib_ks_locrotscale == NULL) poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - - /* now insert the keyframe */ - modify_keyframes(scene, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); + ANIM_apply_keyingset(C, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); /* clear any unkeyed tags */ if (pchan->bone) diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index a162c8eb21a..f20c79da17e 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -849,14 +849,14 @@ void free_posebuf(void) { if (g_posebuf) { bPoseChannel *pchan; - + for (pchan= g_posebuf->chanbase.first; pchan; pchan= pchan->next) { if(pchan->prop) { IDP_FreeProperty(pchan->prop); MEM_freeN(pchan->prop); } } - + /* was copied without constraints */ BLI_freelistN(&g_posebuf->chanbase); MEM_freeN(g_posebuf); @@ -908,9 +908,6 @@ void POSE_OT_copy (wmOperatorType *ot) /* Pointers to the builtin KeyingSets that we want to use */ static KeyingSet *posePaste_ks_locrotscale = NULL; /* the only keyingset we'll need */ -/* transform.h */ -extern void autokeyframe_pose_cb_func(struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode, short targetless_ik); - static int pose_paste_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); @@ -919,13 +916,6 @@ static int pose_paste_exec (bContext *C, wmOperator *op) char name[32]; int flip= RNA_boolean_get(op->ptr, "flipped"); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; - /* sanity checks */ if ELEM(NULL, ob, ob->pose) return OPERATOR_CANCELLED; @@ -974,14 +964,14 @@ static int pose_paste_exec (bContext *C, wmOperator *op) else if (pchan->rotmode == ROT_MODE_AXISANGLE) { /* quat/euler to axis angle */ if (chan->rotmode > 0) - eulO_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,chan->eul, chan->rotmode); + eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode); else - quat_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,chan->quat); + quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat); } else { /* euler/axis-angle to quat */ if (chan->rotmode > 0) - eulO_to_quat( pchan->quat,chan->eul, chan->rotmode); + eulO_to_quat(pchan->quat, chan->eul, chan->rotmode); else axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle); } @@ -998,10 +988,10 @@ static int pose_paste_exec (bContext *C, wmOperator *op) else if (pchan->rotmode == ROT_MODE_AXISANGLE) { float eul[3]; - axis_angle_to_eulO( eul, EULER_ORDER_DEFAULT,pchan->rotAxis, pchan->rotAngle); + axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle); eul[1]*= -1; eul[2]*= -1; - eulO_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,eul, EULER_ORDER_DEFAULT); + eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT); // experimental method (uncomment to test): #if 0 @@ -1013,62 +1003,55 @@ static int pose_paste_exec (bContext *C, wmOperator *op) else { float eul[3]; - quat_to_eul( eul,pchan->quat); + quat_to_eul(eul, pchan->quat); eul[1]*= -1; eul[2]*= -1; - eul_to_quat( pchan->quat,eul); + eul_to_quat(pchan->quat, eul); } } /* ID property */ - if(pchan->prop) { + if (pchan->prop) { IDP_FreeProperty(pchan->prop); MEM_freeN(pchan->prop); pchan->prop= NULL; } - - if(chan->prop) { + + if (chan->prop) pchan->prop= IDP_CopyProperty(chan->prop); + + /* keyframing tagging */ + if (autokeyframe_cfra_can_key(scene, &ob->id)) { + ListBase dsources = {NULL, NULL}; + + /* get KeyingSet to use */ + // TODO: for getting the KeyingSet used, we should really check which channels were affected + // TODO: this should get modified so that custom props are taken into account too! + if (posePaste_ks_locrotscale == NULL) + posePaste_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); + ANIM_apply_keyingset(C, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); + + /* clear any unkeyed tags */ + if (chan->bone) + chan->bone->flag &= ~BONE_UNKEYED; } - - /* auto key, TODO, fix up this INSERTAVAIL vs all other cases */ - if (IS_AUTOKEY_FLAG(INSERTAVAIL) == 0) { /* deal with this case later */ - if (autokeyframe_cfra_can_key(scene, &ob->id)) { - - /* Set keys on pose - * - KeyingSet to use depends on rotation mode - * (but that's handled by the templates code) - */ - // TODO: for getting the KeyingSet used, we should really check which channels were affected - if (posePaste_ks_locrotscale == NULL) - posePaste_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - - modify_keyframes(scene, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); - - /* clear any unkeyed tags */ - if (chan->bone) - chan->bone->flag &= ~BONE_UNKEYED; - } - else { - /* add unkeyed tags */ - if (chan->bone) - chan->bone->flag |= BONE_UNKEYED; - } + else { + /* add unkeyed tags */ + if (chan->bone) + chan->bone->flag |= BONE_UNKEYED; } } } } - - if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { - View3D *v3d= CTX_wm_view3d(C); - autokeyframe_pose_cb_func(C, scene, v3d, ob, TFM_TRANSLATION, 0); - autokeyframe_pose_cb_func(C, scene, v3d, ob, TFM_ROTATION, 0); - autokeyframe_pose_cb_func(C, scene, v3d, ob, TFM_TIME_SCALE, 0); - } - + /* Update event for pose and deformation children */ DAG_id_flush_update(&ob->id, OB_RECALC_DATA); @@ -1077,13 +1060,13 @@ static int pose_paste_exec (bContext *C, wmOperator *op) } else { /* need to trick depgraph, action is not allowed to execute on pose */ + // XXX: this is probably not an issue anymore where_is_pose(scene, ob); ob->recalc= 0; } /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob); - WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); // XXX not really needed, but here for completeness... return OPERATOR_FINISHED; } @@ -1754,13 +1737,7 @@ static int pose_flip_quats_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; + KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); /* loop through all selected pchans, flipping and keying (as needed) */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) @@ -1773,20 +1750,18 @@ static int pose_flip_quats_exec (bContext *C, wmOperator *op) pchan->quat[2]= -pchan->quat[2]; pchan->quat[3]= -pchan->quat[3]; - /* perform auto-keying - * NOTE: paths don't need recalculation here, since the orientations shouldn't have changed - */ + /* tagging */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* Set keys on pose - * - KeyingSet to use depends on rotation mode - * (but that's handled by the templates code) - */ - KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); + ListBase dsources = {NULL, NULL}; - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); /* clear any unkeyed tags */ if (pchan->bone) diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 2c58d9e3ff5..576069d78e8 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -89,8 +89,6 @@ int insert_vert_fcurve(struct FCurve *fcu, float x, float y, short flag); */ short insert_keyframe_direct(struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, short flag); - - /* -------- */ /* Main Keyframing API calls: @@ -106,48 +104,92 @@ short delete_keyframe(struct ID *id, struct bAction *act, const char group[], co /* ************ Keying Sets ********************** */ -/* temporary struct to gather data combos to keyframe - * (is used by modify_keyframes for 'relative' KeyingSets, provided via the dsources arg) - */ -typedef struct bCommonKeySrc { - struct bCommonKeySrc *next, *prev; - - /* general data/destination-source settings */ - struct ID *id; /* id-block this comes from */ +/* forward decl. for this struct which is declared a bit later... */ +struct KeyingSetInfo; + +/* Polling Callback for KeyingSets */ +typedef int (*cbKeyingSet_Poll)(struct KeyingSetInfo *ksi, struct bContext *C); +/* Context Iterator Callback for KeyingSets */ +typedef void (*cbKeyingSet_Iterator)(struct KeyingSetInfo *ksi, struct bContext *C, struct KeyingSet *ks); +/* Property Specifier Callback for KeyingSets (called from iterators) */ +typedef void (*cbKeyingSet_Generate)(struct KeyingSetInfo *ksi, struct bContext *C, struct KeyingSet *ks, struct PointerRNA *ptr); + + +/* Callback info for 'Procedural' KeyingSets to use */ +typedef struct KeyingSetInfo { + struct KeyingSetInfo *next, *prev; + + /* info */ + /* identifier so that user can hook this up to a KeyingSet */ + char name[64]; + /* keying settings */ + short keyingflag; + /* builtin? */ + short builtin; + + /* polling callbacks */ + /* callback for polling the context for whether the right data is available */ + cbKeyingSet_Poll poll; - /* specific cases */ - struct bPoseChannel *pchan; - struct bConstraint *con; -} bCommonKeySrc; + /* generate callbacks */ + /* iterator to use to go through collections of data in context + * - this callback is separate from the 'adding' stage, allowing + * BuiltIn KeyingSets to be manually specified to use + */ + cbKeyingSet_Iterator iter; + /* generator to use to add properties based on the data found by iterator */ + cbKeyingSet_Generate generate; + + /* RNA integration */ + ExtensionRNA ext; +} KeyingSetInfo; /* -------- */ +/* Add another data source for Relative Keying Sets to be evaluated with */ +void ANIM_relative_keyingset_add_source(ListBase *dsources, struct ID *id, struct StructRNA *srna, void *data); + + /* mode for modify_keyframes */ typedef enum eModifyKey_Modes { MODIFYKEY_MODE_INSERT = 0, MODIFYKEY_MODE_DELETE, } eModifyKey_Modes; -/* Keyframing Helper Call - use the provided Keying Set to Add/Remove Keyframes */ -int modify_keyframes(struct Scene *scene, struct ListBase *dsources, struct bAction *act, struct KeyingSet *ks, short mode, float cfra); +/* return codes for errors (with Relative KeyingSets) */ +typedef enum eModifyKey_Returns { + /* context info was invalid for using the Keying Set */ + MODIFYKEY_INVALID_CONTEXT = -1, + /* there isn't any typeinfo for generating paths from context */ + MODIFYKEY_MISSING_TYPEINFO = -2, +} eModifyKey_Returns; -/* -------- */ +/* use the specified KeyingSet to add/remove various Keyframes on the specified frame */ +int ANIM_apply_keyingset(struct bContext *C, ListBase *dsources, struct bAction *act, struct KeyingSet *ks, short mode, float cfra); -/* Generate menu of KeyingSets */ -char *ANIM_build_keyingsets_menu(struct ListBase *list, short for_edit); +/* -------- */ /* Get the first builtin KeyingSet with the given name, which occurs after the given one (or start of list if none given) */ -struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, char name[]); +struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, const char name[]); + +/* Find KeyingSet type info given a name */ +KeyingSetInfo *ANIM_keyingset_info_find_named(const char name[]); -/* Initialise builtin KeyingSets on startup */ -void init_builtin_keyingsets(void); +/* for RNA type registrations... */ +void ANIM_keyingset_info_register(const struct bContext *C, KeyingSetInfo *ksi); +void ANIM_keyingset_info_unregister(const struct bContext *C, KeyingSetInfo *ksi); +/* cleanup on exit */ +void ANIM_keyingset_infos_exit(void); /* -------- */ /* Get the active KeyingSet for the given scene */ struct KeyingSet *ANIM_scene_get_active_keyingset(struct Scene *scene); +/* Check if KeyingSet can be used in the current context */ +short ANIM_keyingset_context_ok_poll(struct bContext *C, struct KeyingSet *ks); + /* ************ Drivers ********************** */ /* Returns whether there is a driver in the copy/paste buffer to paste */ diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 30df347bc60..db15322bbc4 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -75,32 +75,35 @@ static int object_location_clear_exec(bContext *C, wmOperator *op) { - Scene *scene= CTX_data_scene(C); - + Scene *scene = CTX_data_scene(C); KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location"); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); /* clear location of selected objects if not in weight-paint mode */ CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) { - if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) { - if((ob->protectflag & OB_LOCK_LOCX)==0) + if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) { + /* clear location if not locked */ + if ((ob->protectflag & OB_LOCK_LOCX)==0) ob->loc[0]= ob->dloc[0]= 0.0f; - if((ob->protectflag & OB_LOCK_LOCY)==0) + if ((ob->protectflag & OB_LOCK_LOCY)==0) ob->loc[1]= ob->dloc[1]= 0.0f; - if((ob->protectflag & OB_LOCK_LOCZ)==0) + if ((ob->protectflag & OB_LOCK_LOCZ)==0) ob->loc[2]= ob->dloc[2]= 0.0f; - /* do auto-keyframing as appropriate */ + /* auto keyframing */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* init cks for this object, then use the relative KeyingSets to keyframe it */ - cks.id= &ob->id; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + ListBase dsources = {NULL, NULL}; + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); } } + ob->recalc |= OB_RECALC_OB; } CTX_DATA_END; @@ -131,17 +134,12 @@ void OBJECT_OT_location_clear(wmOperatorType *ot) static int object_rotation_clear_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); /* clear rotation of selected objects if not in weight-paint mode */ CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) { if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) { + /* clear rotations that aren't locked */ if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) { if (ob->protectflag & OB_LOCK_ROT4D) { /* perform clamping on a component by component basis */ @@ -233,13 +231,21 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op) } } - /* do auto-keyframing as appropriate */ + /* auto keyframing */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* init cks for this object, then use the relative KeyingSets to keyframe it */ - cks.id= &ob->id; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + ListBase dsources = {NULL, NULL}; + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); } } + ob->recalc |= OB_RECALC_OB; } CTX_DATA_END; @@ -270,35 +276,37 @@ void OBJECT_OT_rotation_clear(wmOperatorType *ot) static int object_scale_clear_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scaling"); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); /* clear scales of selected objects if not in weight-paint mode */ CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) { if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) { - if((ob->protectflag & OB_LOCK_SCALEX)==0) { + /* clear scale factors which are not locked */ + if ((ob->protectflag & OB_LOCK_SCALEX)==0) { ob->dsize[0]= 0.0f; ob->size[0]= 1.0f; } - if((ob->protectflag & OB_LOCK_SCALEY)==0) { + if ((ob->protectflag & OB_LOCK_SCALEY)==0) { ob->dsize[1]= 0.0f; ob->size[1]= 1.0f; } - if((ob->protectflag & OB_LOCK_SCALEZ)==0) { + if ((ob->protectflag & OB_LOCK_SCALEZ)==0) { ob->dsize[2]= 0.0f; ob->size[2]= 1.0f; } - /* do auto-keyframing as appropriate */ + /* auto keyframing */ if (autokeyframe_cfra_can_key(scene, &ob->id)) { - /* init cks for this object, then use the relative KeyingSets to keyframe it */ - cks.id= &ob->id; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + ListBase dsources = {NULL, NULL}; + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); } } ob->recalc |= OB_RECALC_OB; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 38a7163d35f..828d5368834 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -2323,7 +2323,7 @@ static void flyEvent(FlyInfo *fly, wmEvent *event) } } -static int flyApply(FlyInfo *fly) +static int flyApply(bContext *C, FlyInfo *fly) { /* fly mode - Shift+F @@ -2606,13 +2606,10 @@ static int flyApply(FlyInfo *fly) /* record the motion */ if (autokeyframe_cfra_can_key(scene, id_key)) { - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; - int cfra = CFRA; + ListBase dsources = {NULL, NULL}; - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= id_key; + /* add datasource override for the camera object */ + ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); /* insert keyframes * 1) on the first frame @@ -2621,12 +2618,15 @@ static int flyApply(FlyInfo *fly) */ if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); } if (fly->speed) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location"); - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); } + + /* free temp data */ + BLI_freelistN(&dsources); } } } else @@ -2689,7 +2689,7 @@ static int fly_modal(bContext *C, wmOperator *op, wmEvent *event) flyEvent(fly, event); if(event->type==TIMER && event->customdata == fly->timer) - flyApply(fly); + flyApply(C, fly); if(fly->redraw) { ED_region_tag_redraw(CTX_wm_region(C)); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 372aa42bac3..9c570e10406 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -102,20 +102,7 @@ #include "BKE_report.h" #include "BKE_scene.h" -//#include "BIF_editview.h" -//#include "BIF_editlattice.h" -//#include "BIF_editconstraint.h" -//#include "BIF_editmesh.h" -//#include "BIF_editsima.h" -//#include "BIF_editparticle.h" #include "BIF_gl.h" -//#include "BIF_poseobject.h" -//#include "BIF_meshtools.h" -//#include "BIF_mywindow.h" -//#include "BIF_resources.h" -//#include "BIF_screen.h" -//#include "BIF_space.h" -//#include "BIF_toolbox.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -132,19 +119,11 @@ #include "UI_view2d.h" -//#include "BSE_edit.h" -//#include "BDR_editobject.h" // reset_slowparents() -//#include "BDR_gpencil.h" - #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" -//#include "editmesh.h" -// -//#include "blendef.h" -// -//#include "mydevice.h" +#include "RNA_access.h" extern ListBase editelems; @@ -4484,20 +4463,21 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, // TODO: this should probably be done per channel instead... if (autokeyframe_cfra_can_key(scene, id)) { KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; + ListBase dsources = {NULL, NULL}; float cfra= (float)CFRA; // xxx this will do for now short flag = 0; - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; - + /* get flags used for inserting keyframes */ flag = ANIM_get_keyframing_flags(scene, 1); + /* add datasource override for the camera object */ + ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL); + if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) { - /* only insert into active keyingset */ - modify_keyframes(scene, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); + /* only insert into active keyingset + * NOTE: we assume here that the active Keying Set does not need to have its iterator overridden spe + */ + ANIM_apply_keyingset(C, NULL, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); } else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { AnimData *adt= ob->adt; @@ -4543,22 +4523,25 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */ if (doLoc) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location"); - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doRot) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doScale) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scale"); - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } } /* insert keyframe in all (transform) channels */ else { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } + + /* free temp info */ + BLI_freelistN(&dsources); } } @@ -4579,15 +4562,9 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o // TODO: this should probably be done per channel instead... if (autokeyframe_cfra_can_key(scene, id)) { KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); - bCommonKeySrc cks; - ListBase dsources = {&cks, &cks}; float cfra= (float)CFRA; short flag= 0; - /* init common-key-source for use by KeyingSets */ - memset(&cks, 0, sizeof(bCommonKeySrc)); - cks.id= &ob->id; - /* flag is initialised from UserPref keyframing settings * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get * visual keyframes even if flag not set, as it's not that useful otherwise @@ -4600,14 +4577,18 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) { if (pchan->bone->flag & BONE_TRANSFORM) { + ListBase dsources = {NULL, NULL}; + /* clear any 'unkeyed' flag it may have */ pchan->bone->flag &= ~BONE_UNKEYED; + /* add datasource override for the camera object */ + ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); + /* only insert into active keyingset? */ + // TODO: move this first case out of the loop if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) { - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, NULL, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); } /* only insert into available channels? */ else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { @@ -4656,34 +4637,25 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o if (doLoc) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location"); - - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doRot) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); - - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doScale) { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scale"); - - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } } /* insert keyframe in all (transform) channels */ else { KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - - /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ - cks.pchan= pchan; - modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } + + /* free temp info */ + BLI_freelistN(&dsources); } } diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index d2755f71fa3..8e46cfefba5 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -663,20 +663,19 @@ typedef enum eNlaTrack_Flag { typedef struct KS_Path { struct KS_Path *next, *prev; - /* absolute paths only */ ID *id; /* ID block that keyframes are for */ char group[64]; /* name of the group to add to */ - /* relative paths only */ int idtype; /* ID-type that path can be used on */ - int templates; /* Templates that will be encountered in the path (as set of bitflags) */ - /* all paths */ + short groupmode; /* group naming (eKSP_Grouping) */ + short pad; + char *rna_path; /* dynamically (or statically in the case of predefined sets) path */ int array_index; /* index that path affects */ short flag; /* various settings, etc. */ - short groupmode; /* group naming (eKSP_Grouping) */ + short keyingflag; /* settings to supply insertkey() with */ } KS_Path; /* KS_Path->flag */ @@ -734,6 +733,7 @@ typedef struct KeyingSet { ListBase paths; /* (KS_Path) paths to keyframe to */ char name[64]; /* user-viewable name for KeyingSet (for menus, etc.) */ + char typeinfo[64]; /* name of the typeinfo data used for the relative paths */ short flag; /* settings for KeyingSet */ short keyingflag; /* settings to supply insertkey() with */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index ae431beb1fe..e50b1b7ad58 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -257,6 +257,7 @@ extern StructRNA RNA_KeyConfig; extern StructRNA RNA_Keyframe; extern StructRNA RNA_KeyingSet; extern StructRNA RNA_KeyingSetPath; +extern StructRNA RNA_KeyingSetInfo; extern StructRNA RNA_KeyMap; extern StructRNA RNA_KeyMapItem; extern StructRNA RNA_KinematicConstraint; diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 453d9b9a844..e048a79daf8 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -37,12 +37,13 @@ #include "MEM_guardedalloc.h" +#include "ED_keyframing.h" + /* exported for use in API */ EnumPropertyItem keyingset_path_grouping_items[] = { {KSP_GROUP_NAMED, "NAMED", 0, "Named Group", ""}, {KSP_GROUP_NONE, "NONE", 0, "None", ""}, {KSP_GROUP_KSNAME, "KEYINGSET", 0, "Keying Set Name", ""}, - {KSP_GROUP_TEMPLATE_ITEM, "TEMPLATE", 0, "Innermost Context-Item Name", ""}, {0, NULL, 0, NULL, NULL}}; #ifdef RNA_RUNTIME @@ -66,6 +67,152 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) /* ****************************** */ +/* wrapper for poll callback */ +static int RKS_POLL_rna_internal(KeyingSetInfo *ksi, bContext *C) +{ + PointerRNA ptr; + ParameterList list; + FunctionRNA *func; + void *ret; + int ok; + + RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr); + func= RNA_struct_find_function(&ptr, "poll"); + + RNA_parameter_list_create(&list, &ptr, func); + /* hook up arguments */ + RNA_parameter_set_lookup(&list, "ksi", &ksi); + RNA_parameter_set_lookup(&list, "context", &C); + + /* execute the function */ + ksi->ext.call(&ptr, func, &list); + + /* read the result */ + RNA_parameter_get_lookup(&list, "ok", &ret); + ok= *(int*)ret; + RNA_parameter_list_free(&list); + + return ok; +} + +/* wrapper for iterator callback */ +static void RKS_ITER_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks) +{ + PointerRNA ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr); + func= RNA_struct_find_function(&ptr, "iterator"); + + RNA_parameter_list_create(&list, &ptr, func); + /* hook up arguments */ + RNA_parameter_set_lookup(&list, "ksi", &ksi); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "ks", &ks); + + /* execute the function */ + ksi->ext.call(&ptr, func, &list); + RNA_parameter_list_free(&list); +} + +/* wrapper for generator callback */ +static void RKS_GEN_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks, PointerRNA *data) +{ + PointerRNA ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr); + func= RNA_struct_find_function(&ptr, "iterator"); + + RNA_parameter_list_create(&list, &ptr, func); + /* hook up arguments */ + RNA_parameter_set_lookup(&list, "ksi", &ksi); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "ks", &ks); + RNA_parameter_set_lookup(&list, "data", &data); + + /* execute the function */ + ksi->ext.call(&ptr, func, &list); + RNA_parameter_list_free(&list); +} + +/* ------ */ + +// XXX: the exact purpose of this is not too clear... maybe we want to revise this at some point? +static StructRNA *rna_KeyingSetInfo_refine(PointerRNA *ptr) +{ + KeyingSetInfo *ksi= (KeyingSetInfo *)ptr->data; + return (ksi->ext.srna)? ksi->ext.srna: &RNA_KeyingSetInfo; +} + +static void rna_KeyingSetInfo_unregister(const bContext *C, StructRNA *type) +{ + KeyingSetInfo *ksi= RNA_struct_blender_type_get(type); + + if (ksi == NULL) + return; + + /* free RNA data referencing this */ + RNA_struct_free_extension(type, &ksi->ext); + RNA_struct_free(&BLENDER_RNA, type); + + /* unlink Blender-side data */ + ANIM_keyingset_info_unregister(C, ksi); +} + +static StructRNA *rna_KeyingSetInfo_register(const bContext *C, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +{ + KeyingSetInfo dummyksi = {0}; + KeyingSetInfo *ksi; + PointerRNA dummyptr; + int have_function[3]; + + /* setup dummy type info to store static properties in */ + // TODO: perhaps we want to get users to register as if they're using 'KeyingSet' directly instead? + RNA_pointer_create(NULL, &RNA_KeyingSetInfo, &dummyksi, &dummyptr); + + /* validate the python class */ + if (validate(&dummyptr, data, have_function) != 0) + return NULL; + + if (strlen(identifier) >= sizeof(dummyksi.name)) { + BKE_reportf(reports, RPT_ERROR, "registering keying set info class: '%s' is too long, maximum length is %d.", identifier, sizeof(dummyksi.name)); + return NULL; + } + + /* check if we have registered this info before, and remove it */ + ksi = ANIM_keyingset_info_find_named(dummyksi.name); + if (ksi && ksi->ext.srna) + rna_KeyingSetInfo_unregister(C, ksi->ext.srna); + + /* create a new KeyingSetInfo type */ + ksi= MEM_callocN(sizeof(KeyingSetInfo), "python keying set info"); + memcpy(ksi, &dummyksi, sizeof(KeyingSetInfo)); + + /* set RNA-extensions info */ + ksi->ext.srna= RNA_def_struct(&BLENDER_RNA, ksi->name, "KeyingSetInfo"); + ksi->ext.data= data; + ksi->ext.call= call; + ksi->ext.free= free; + RNA_struct_blender_type_set(ksi->ext.srna, ksi); + + /* set callbacks */ + // NOTE: we really should have all of these... + ksi->poll= (have_function[0])? RKS_POLL_rna_internal: NULL; + ksi->iter= (have_function[1])? RKS_ITER_rna_internal: NULL; + ksi->generate= (have_function[2])? RKS_GEN_rna_internal: NULL; + + /* add and register with other info as needed */ + ANIM_keyingset_info_register(C, ksi); + + /* return the struct-rna added */ + return ksi->ext.srna; +} + +/* ****************************** */ + static StructRNA *rna_ksPath_id_typef(PointerRNA *ptr) { KS_Path *ksp= (KS_Path*)ptr->data; @@ -123,6 +270,14 @@ static void rna_ksPath_RnaPath_set(PointerRNA *ptr, const char *value) /* ****************************** */ +static int rna_KeyingSet_typeinfo_name_editable(PointerRNA *ptr) +{ + KeyingSet *ks= (KeyingSet *)ptr->data; + + /* only editable if we're using relative paths */ + return ((ks->flag & KEYINGSET_ABSOLUTE)==0); +} + static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr) { KeyingSet *ks= (KeyingSet *)ptr->data; @@ -167,6 +322,91 @@ static void rna_KeyingSet_active_ksPath_index_range(PointerRNA *ptr, int *min, i #else +/* helper function for Keying Set -> keying settings */ +static void rna_def_common_keying_flags(StructRNA *srna, short reg) +{ + PropertyRNA *prop; + + prop= RNA_def_property(srna, "insertkey_needed", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_NEEDED); + RNA_def_property_ui_text(prop, "Insert Keyframes - Only Needed", "Only insert keyframes where they're needed in the relevant F-Curves"); + if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + + prop= RNA_def_property(srna, "insertkey_visual", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_MATRIX); + RNA_def_property_ui_text(prop, "Insert Keyframes - Visual", "Insert keyframes based on 'visual transforms'"); + if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + + prop= RNA_def_property(srna, "insertkey_xyz_to_rgb", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_XYZ2RGB); + RNA_def_property_ui_text(prop, "F-Curve Colors - XYZ to RGB", "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis"); + if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); +} + +/* --- */ + +static void rna_def_keyingset_info(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + + srna= RNA_def_struct(brna, "KeyingSetInfo", NULL); + RNA_def_struct_sdna(srna, "KeyingSetInfo"); + RNA_def_struct_ui_text(srna, "Keying Set Info", "Callback function defines for relative Keying Sets"); + RNA_def_struct_refine_func(srna, "rna_KeyingSetInfo_refine"); + RNA_def_struct_register_funcs(srna, "rna_KeyingSetInfo_register", "rna_KeyingSetInfo_unregister"); + + /* Properties --------------------- */ + + RNA_define_verify_sdna(0); // not in sdna + + /* Name */ + prop= RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_flag(prop, PROP_REGISTER); + + prop= RNA_def_property(srna, "bl_builtin", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "builtin", 1); + RNA_def_property_ui_text(prop, "BuiltIn", "Keying Set type is required internally."); + RNA_def_property_flag(prop, PROP_REGISTER); + + rna_def_common_keying_flags(srna, 1); /* '1' arg here is to indicate that we need these to be set on registering */ + + RNA_define_verify_sdna(1); + + /* Function Callbacks ------------- */ + /* poll */ + func= RNA_def_function(srna, "poll", NULL); + RNA_def_function_ui_description(func, "Test if Keying Set can be used or not"); + RNA_def_function_flag(func, FUNC_REGISTER); + RNA_def_function_return(func, RNA_def_boolean(func, "ok", 1, "", "")); + parm= RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + + /* iterator */ + func= RNA_def_function(srna, "iterator", NULL); + RNA_def_function_ui_description(func, "Call generate() on the structs which have properties to be keyframed"); + RNA_def_function_flag(func, FUNC_REGISTER); + parm= RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "ks", "KeyingSet", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + + /* generate */ + func= RNA_def_function(srna, "generate", NULL); + RNA_def_function_ui_description(func, "Add Paths to the Keying Set to keyframe the properties of the given data"); + RNA_def_function_flag(func, FUNC_REGISTER); + parm= RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "ks", "KeyingSet", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "data", NULL, "", ""); // "AnyType"... + RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); +} static void rna_def_keyingset_path(BlenderRNA *brna) { @@ -215,6 +455,9 @@ static void rna_def_keyingset_path(BlenderRNA *brna) prop= RNA_def_property(srna, "entire_array", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", KSP_FLAG_WHOLE_ARRAY); RNA_def_property_ui_text(prop, "Entire Array", "When an 'array/vector' type is chosen (Location, Rotation, Color, etc.), entire array is to be used"); + + /* Keyframing Settings */ + rna_def_common_keying_flags(srna, 0); } static void rna_def_keyingset(BlenderRNA *brna) @@ -230,6 +473,13 @@ static void rna_def_keyingset(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Name", ""); RNA_def_struct_name_property(srna, prop); + /* TypeInfo associated with Relative KeyingSet (only) */ + prop= RNA_def_property(srna, "typeinfo_name", PROP_STRING, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_string_sdna(prop, NULL, "typeinfo"); + RNA_def_property_editable_func(prop, "rna_KeyingSet_typeinfo_name_editable"); + RNA_def_property_ui_text(prop, "TypeInfo Name", ""); + /* Paths */ prop= RNA_def_property(srna, "paths", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "paths", NULL); @@ -249,28 +499,13 @@ static void rna_def_keyingset(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Active Path Index", "Current Keying Set index"); /* Flags */ - // XXX: depreceated - prop= RNA_def_property(srna, "builtin", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYINGSET_BUILTIN); - RNA_def_property_ui_text(prop, "Built-In", "Keying Set is a built-in to Blender"); - prop= RNA_def_property(srna, "absolute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYINGSET_ABSOLUTE); RNA_def_property_ui_text(prop, "Absolute", "Keying Set defines specific paths/settings to be keyframed (i.e. is not reliant on context info)"); /* Keyframing Flags */ - prop= RNA_def_property(srna, "insertkey_needed", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_NEEDED); - RNA_def_property_ui_text(prop, "Insert Keyframes - Only Needed", "Only insert keyframes where they're needed in the relevant F-Curves"); - - prop= RNA_def_property(srna, "insertkey_visual", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_MATRIX); - RNA_def_property_ui_text(prop, "Insert Keyframes - Visual", "Insert keyframes based on 'visual transforms'"); + rna_def_common_keying_flags(srna, 0); - prop= RNA_def_property(srna, "insertkey_xyz_to_rgb", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_XYZ2RGB); - RNA_def_property_ui_text(prop, "F-Curve Colors - XYZ to RGB", "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis"); /* Keying Set API */ RNA_api_keyingset(srna); @@ -347,6 +582,7 @@ void RNA_def_animation(BlenderRNA *brna) rna_def_keyingset(brna); rna_def_keyingset_path(brna); + rna_def_keyingset_info(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_animation_api.c b/source/blender/makesrna/intern/rna_animation_api.c index b07f147ac96..46ecc8679e7 100644 --- a/source/blender/makesrna/intern/rna_animation_api.c +++ b/source/blender/makesrna/intern/rna_animation_api.c @@ -41,10 +41,11 @@ #include "BKE_animsys.h" -static void rna_KeyingSet_add_path(KeyingSet *keyingset, ReportList *reports, +static KS_Path *rna_KeyingSet_add_path(KeyingSet *keyingset, ReportList *reports, ID *id, char rna_path[], int array_index, int entire_array, int grouping_method, char group_name[]) { + KS_Path *ksp = NULL; short flag = 0; /* validate flags */ @@ -53,12 +54,31 @@ static void rna_KeyingSet_add_path(KeyingSet *keyingset, ReportList *reports, /* if data is valid, call the API function for this */ if (keyingset) { - BKE_keyingset_add_path(keyingset, id, group_name, rna_path, array_index, flag, grouping_method); + ksp= BKE_keyingset_add_path(keyingset, id, group_name, rna_path, array_index, flag, grouping_method); keyingset->active_path= BLI_countlist(&keyingset->paths); } else { BKE_report(reports, RPT_ERROR, "Keying Set Path could not be added."); } + + /* return added path */ + return ksp; +} + +static void rna_KeyingSet_remove_path(KeyingSet *keyingset, ReportList *reports, KS_Path *ksp) +{ + /* if data is valid, call the API function for this */ + if (keyingset && ksp) { + /* remove the active path from the KeyingSet */ + BKE_keyingset_free_path(keyingset, ksp); + + /* the active path number will most likely have changed */ + // TODO: we should get more fancy and actually check if it was removed, but this will do for now + keyingset->active_path = 0; + } + else { + BKE_report(reports, RPT_ERROR, "Keying Set Path could not be removed."); + } } #else @@ -68,10 +88,13 @@ void RNA_api_keyingset(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - /* Add Destination */ + /* Add Path */ func= RNA_def_function(srna, "add_path", "rna_KeyingSet_add_path"); - RNA_def_function_ui_description(func, "Add a new destination for the Keying Set."); + RNA_def_function_ui_description(func, "Add a new path for the Keying Set."); RNA_def_function_flag(func, FUNC_USE_REPORTS); + /* return arg */ + parm= RNA_def_pointer(func, "ksp", "KeyingSetPath", "New Path", "Path created and added to the Keying Set"); + RNA_def_function_return(func, parm); /* ID-block for target */ parm= RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID-Datablock for the destination."); RNA_def_property_flag(parm, PROP_REQUIRED); @@ -84,6 +107,14 @@ void RNA_api_keyingset(StructRNA *srna) /* grouping */ parm=RNA_def_enum(func, "grouping_method", keyingset_path_grouping_items, KSP_GROUP_KSNAME, "Grouping Method", "Method used to define which Group-name to use."); parm=RNA_def_string(func, "group_name", "", 64, "Group Name", "Name of Action Group to assign destination to (only if grouping mode is to use this name)."); + + /* Remove Path */ + func= RNA_def_function(srna, "remove_path", "rna_KeyingSet_remove_path"); + RNA_def_function_ui_description(func, "Remove the given path from the Keying Set."); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + /* path to remove */ + parm= RNA_def_pointer(func, "path", "KeyingSetPath", "Path", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); } #endif diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 5302cb1eaaf..ae310a7f59d 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -128,8 +128,6 @@ void WM_init(bContext *C, int argc, char **argv) BLF_init(11, U.dpi); BLF_lang_init(); - init_builtin_keyingsets(); /* editors/animation/keyframing.c */ - /* get the default database, plus a wm */ WM_read_homefile(C, NULL); @@ -281,7 +279,9 @@ void WM_exit(bContext *C) // fsmenu_free(); BLF_exit(); - + + ANIM_keyingset_infos_exit(); + RE_FreeAllRender(); RE_engines_exit(); |