Animation: Sensible frame range for motion paths

Motion paths can now be initialised to more sensible frame ranges,
rather than simply 1-250:

    - Scene Frame Range
    - Selected Keyframes
    - All Keyframes

Reviewed By: sybren, looch, dfelinto, pablico

Maniphest Tasks: T93047

Differential Revision: https://developer.blender.org/D13687
This commit is contained in:
Colin Marmond 2022-04-26 12:29:22 +02:00 committed by Sybren A. Stüvel
parent 6cf148227b
commit 4e57b6ce77
Notes: blender-bot 2023-02-13 17:08:28 +01:00
Referenced by issue #101522, Motion Paths: 'Update Paths' inconveniently restores frame range
Referenced by issue #93047, Use other frame range for new motion paths instead of 1-250
14 changed files with 222 additions and 144 deletions

View File

@ -24,14 +24,9 @@ class MotionPathButtonsPanel:
layout.use_property_split = True
layout.use_property_decorate = False
row = layout.row(align=True)
row.prop(mps, "type")
if mps.type == 'RANGE':
if bones:
row.operator("pose.paths_range_update", text="", icon='TIME')
else:
row.operator("object.paths_range_update", text="", icon='TIME')
# Display Range
col = layout.column(align=True)
col.prop(mps, "type")
if mps.type == 'CURRENT_FRAME':
col = layout.column(align=True)
col.prop(mps, "frame_before", text="Frame Range Before")
@ -43,21 +38,28 @@ class MotionPathButtonsPanel:
col.prop(mps, "frame_end", text="End")
col.prop(mps, "frame_step", text="Step")
# Calculation Range
col = layout.column(align=True)
col.prop(mps, "range", text="Calculation Range")
if mpath:
col = layout.column(align=True)
col.enabled = False
if bones:
col.prop(mpath, "frame_start", text="Bone Cache From")
else:
col.prop(mpath, "frame_start", text="Cache From")
col.prop(mpath, "frame_end", text="To")
row = col.row(align=True)
row.enabled = False
row.prop(mpath, "frame_start", text="Cached Range")
row.prop(mpath, "frame_end", text="")
col = layout.column(align=True)
if bones:
col.operator("pose.paths_update", text="Update Paths", icon='BONE_DATA')
col.operator("pose.paths_update", text="Update Path", icon='BONE_DATA')
row = col.row(align=True)
row.operator("object.paths_update_visible", text="Update All Paths", icon='WORLD')
row.operator("pose.paths_clear", text="", icon='X')
else:
col.operator("object.paths_update", text="Update Paths", icon='OBJECT_DATA')
col.operator("object.paths_update", text="Update Path", icon='OBJECT_DATA')
row = col.row(align=True)
row.operator("object.paths_update_visible", text="Update All Paths", icon='WORLD')
row.operator("object.paths_clear", text="", icon='X')
else:
col = layout.column(align=True)
col.label(text="Nothing to show yet...", icon='ERROR')
@ -67,12 +69,12 @@ class MotionPathButtonsPanel:
else:
col.operator("object.paths_calculate", text="Calculate...", icon='OBJECT_DATA')
row = col.row(align=True)
row.operator("object.paths_update_visible", text="Update All Paths", icon='WORLD')
if bones:
row.operator("pose.paths_clear", text="", icon='X')
else:
row.operator("object.paths_clear", text="", icon='X')
row = col.row(align=True)
row.operator("object.paths_update_visible", text="Update All Paths", icon='WORLD')
if bones:
row.operator("pose.paths_clear", text="", icon='X')
else:
row.operator("object.paths_clear", text="", icon='X')
class MotionPathButtonsPanel_display:

View File

@ -153,6 +153,8 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports,
if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) {
/* outer check ensures that we have some curve data for this path */
if (mpath->length == expected_length) {
mpath->start_frame = avs->path_sf;
mpath->end_frame = avs->path_ef;
/* return/use this as it is already valid length */
return mpath;
}

View File

@ -340,6 +340,43 @@ static void motionpath_free_free_tree_data(ListBase *targets)
}
}
void animviz_motionpath_compute_range(Object *ob, Scene *scene)
{
bAnimVizSettings *avs = ob->mode == OB_MODE_POSE ? &ob->pose->avs : &ob->avs;
const bool has_action = ob->adt && ob->adt->action;
if (avs->path_range == MOTIONPATH_RANGE_SCENE || !has_action ||
BLI_listbase_is_empty(&ob->adt->action->curves)) {
avs->path_sf = PSFRA;
avs->path_ef = PEFRA;
return;
}
struct AnimKeylist *keylist = ED_keylist_create();
LISTBASE_FOREACH (FCurve *, fcu, &ob->adt->action->curves) {
fcurve_to_keylist(ob->adt, fcu, keylist, 0);
}
Range2f frame_range;
switch (avs->path_range) {
case MOTIONPATH_RANGE_KEYS_SELECTED:
if (ED_keylist_selected_keys_frame_range(keylist, &frame_range)) {
break;
}
ATTR_FALLTHROUGH; // Fall through if there were no selected keys found.
case MOTIONPATH_RANGE_KEYS_ALL:
ED_keylist_all_keys_frame_range(keylist, &frame_range);
break;
case MOTIONPATH_RANGE_SCENE:
BLI_assert_msg(false, "This should not happen, function should have exited earlier.");
};
avs->path_sf = frame_range.min;
avs->path_ef = frame_range.max;
ED_keylist_free(keylist);
}
void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,

View File

@ -304,7 +304,21 @@ const struct ListBase *ED_keylist_listbase(const AnimKeylist *keylist)
return &keylist->key_columns;
}
bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range)
static void keylist_first_last(const struct AnimKeylist *keylist,
const struct ActKeyColumn **first_column,
const struct ActKeyColumn **last_column)
{
if (keylist->is_runtime_initialized) {
*first_column = &keylist->runtime.key_columns[0];
*last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
}
else {
*first_column = static_cast<const ActKeyColumn *>(keylist->key_columns.first);
*last_column = static_cast<const ActKeyColumn *>(keylist->key_columns.last);
}
}
bool ED_keylist_all_keys_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range)
{
BLI_assert(r_frame_range);
@ -314,13 +328,33 @@ bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_
const ActKeyColumn *first_column;
const ActKeyColumn *last_column;
if (keylist->is_runtime_initialized) {
first_column = &keylist->runtime.key_columns[0];
last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
keylist_first_last(keylist, &first_column, &last_column);
r_frame_range->min = first_column->cfra;
r_frame_range->max = last_column->cfra;
return true;
}
bool ED_keylist_selected_keys_frame_range(const struct AnimKeylist *keylist,
Range2f *r_frame_range)
{
BLI_assert(r_frame_range);
if (ED_keylist_is_empty(keylist)) {
return false;
}
else {
first_column = static_cast<const ActKeyColumn *>(keylist->key_columns.first);
last_column = static_cast<const ActKeyColumn *>(keylist->key_columns.last);
const ActKeyColumn *first_column;
const ActKeyColumn *last_column;
keylist_first_last(keylist, &first_column, &last_column);
while (first_column && !(first_column->sel & SELECT)) {
first_column = first_column->next;
}
while (last_column && !(last_column->sel & SELECT)) {
last_column = last_column->prev;
}
if (!first_column || !last_column || first_column == last_column) {
return false;
}
r_frame_range->min = first_column->cfra;
r_frame_range->max = last_column->cfra;

View File

@ -222,16 +222,15 @@ static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEven
bAnimVizSettings *avs = &ob->pose->avs;
PointerRNA avs_ptr;
RNA_int_set(op->ptr, "start_frame", avs->path_sf);
RNA_int_set(op->ptr, "end_frame", avs->path_ef);
RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
RNA_enum_set(op->ptr, "display_type", RNA_enum_get(&avs_ptr, "type"));
RNA_enum_set(op->ptr, "range", RNA_enum_get(&avs_ptr, "range"));
RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
}
/* show popup dialog to allow editing of range... */
/* FIXME: hard-coded dimensions here are just arbitrary. */
return WM_operator_props_dialog_popup(C, op, 200);
return WM_operator_props_dialog_popup(C, op, 270);
}
/* For the object with pose/action: create path curves for selected bones
@ -251,8 +250,9 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
bAnimVizSettings *avs = &ob->pose->avs;
PointerRNA avs_ptr;
avs->path_sf = RNA_int_get(op->ptr, "start_frame");
avs->path_ef = RNA_int_get(op->ptr, "end_frame");
avs->path_type = RNA_enum_get(op->ptr, "display_type");
avs->path_range = RNA_enum_get(op->ptr, "range");
animviz_motionpath_compute_range(ob, scene);
RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
RNA_enum_set(&avs_ptr, "bake_location", RNA_enum_get(op->ptr, "bake_location"));
@ -299,24 +299,18 @@ void POSE_OT_paths_calculate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
RNA_def_int(ot->srna,
"start_frame",
1,
MINAFRAME,
MAXFRAME,
"Start",
"First frame to calculate bone paths on",
MINFRAME,
MAXFRAME / 2.0);
RNA_def_int(ot->srna,
"end_frame",
250,
MINAFRAME,
MAXFRAME,
"End",
"Last frame to calculate bone paths on",
MINFRAME,
MAXFRAME / 2.0);
RNA_def_enum(ot->srna,
"display_type",
rna_enum_motionpath_display_type_items,
MOTIONPATH_TYPE_RANGE,
"Display type",
"");
RNA_def_enum(ot->srna,
"range",
rna_enum_motionpath_range_items,
MOTIONPATH_RANGE_SCENE,
"Computation Range",
"");
RNA_def_enum(ot->srna,
"bake_location",
@ -338,7 +332,7 @@ static bool pose_update_paths_poll(bContext *C)
return false;
}
static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
static int pose_update_paths_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
Scene *scene = CTX_data_scene(C);
@ -346,6 +340,13 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
if (ELEM(NULL, ob, scene)) {
return OPERATOR_CANCELLED;
}
animviz_motionpath_compute_range(ob, scene);
/* set up path data for bones being calculated */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object) {
animviz_verify_motionpaths(op->reports, scene, ob, pchan);
}
CTX_DATA_END;
/* Calculate the bones that now have motion-paths. */
/* TODO: only make for the selected bones? */

View File

@ -1096,6 +1096,15 @@ void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
eAnimvizCalcRange range,
bool restore);
/**
* Update motion path computation range (in ob.avs or armature.avs) from user choice in
* ob.avs.path_range or arm.avs.path_range, depending on active user mode.
*
* @param ob: Object to compute range for (must be provided)
* @param scene: Used when scene range is choosen
*/
void animviz_motionpath_compute_range(struct Object *ob, struct Scene *scene);
/**
* Get list of motion paths to be baked for the given object.
* - assumes the given list is ready to be used.

View File

@ -131,7 +131,11 @@ const struct ActKeyColumn *ED_keylist_find_any_between(const struct AnimKeylist
const Range2f frame_range);
bool ED_keylist_is_empty(const struct AnimKeylist *keylist);
const struct ListBase /* ActKeyColumn */ *ED_keylist_listbase(const struct AnimKeylist *keylist);
bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range);
bool ED_keylist_all_keys_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range);
/* Return the selected keyframe's range. If none are selected, return False and
* do not affect the frame range. */
bool ED_keylist_selected_keys_frame_range(const struct AnimKeylist *keylist,
Range2f *r_frame_range);
const ActKeyColumn *ED_keylist_array(const struct AnimKeylist *keylist);
int64_t ED_keylist_array_len(const struct AnimKeylist *keylist);

View File

@ -74,6 +74,7 @@
#include "ED_curve.h"
#include "ED_gpencil.h"
#include "ED_image.h"
#include "ED_keyframes_keylist.h"
#include "ED_lattice.h"
#include "ED_mball.h"
#include "ED_mesh.h"
@ -1207,30 +1208,29 @@ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEv
/* set default settings from existing/stored settings */
{
bAnimVizSettings *avs = &ob->avs;
RNA_int_set(op->ptr, "start_frame", avs->path_sf);
RNA_int_set(op->ptr, "end_frame", avs->path_ef);
RNA_enum_set(op->ptr, "display_type", avs->path_type);
RNA_enum_set(op->ptr, "range", avs->path_range);
}
/* show popup dialog to allow editing of range... */
/* FIXME: hard-coded dimensions here are just arbitrary. */
return WM_operator_props_dialog_popup(C, op, 200);
return WM_operator_props_dialog_popup(C, op, 270);
}
/* Calculate/recalculate whole paths (avs.path_sf to avs.path_ef) */
static int object_calculate_paths_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
int start = RNA_int_get(op->ptr, "start_frame");
int end = RNA_int_get(op->ptr, "end_frame");
short path_type = RNA_enum_get(op->ptr, "display_type");
short path_range = RNA_enum_get(op->ptr, "range");
/* set up path data for bones being calculated */
/* set up path data for objects being calculated */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
bAnimVizSettings *avs = &ob->avs;
/* grab baking settings from operator settings */
avs->path_sf = start;
avs->path_ef = end;
avs->path_type = path_type;
avs->path_range = path_range;
animviz_motionpath_compute_range(ob, scene);
/* verify that the selected object has the appropriate settings */
animviz_verify_motionpaths(op->reports, scene, ob, NULL);
@ -1249,9 +1249,9 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
void OBJECT_OT_paths_calculate(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Calculate Object Paths";
ot->name = "Calculate Object Motion Paths";
ot->idname = "OBJECT_OT_paths_calculate";
ot->description = "Calculate motion paths for the selected objects";
ot->description = "Generate motion paths for the selected objects";
/* api callbacks */
ot->invoke = object_calculate_paths_invoke;
@ -1262,24 +1262,18 @@ void OBJECT_OT_paths_calculate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
RNA_def_int(ot->srna,
"start_frame",
1,
MINAFRAME,
MAXFRAME,
"Start",
"First frame to calculate object paths on",
MINFRAME,
MAXFRAME / 2.0);
RNA_def_int(ot->srna,
"end_frame",
250,
MINAFRAME,
MAXFRAME,
"End",
"Last frame to calculate object paths on",
MINFRAME,
MAXFRAME / 2.0);
RNA_def_enum(ot->srna,
"display_type",
rna_enum_motionpath_display_type_items,
MOTIONPATH_TYPE_RANGE,
"Display type",
"");
RNA_def_enum(ot->srna,
"range",
rna_enum_motionpath_range_items,
MOTIONPATH_RANGE_SCENE,
"Computation Range",
"");
}
/** \} */
@ -1298,13 +1292,19 @@ static bool object_update_paths_poll(bContext *C)
return false;
}
static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
static int object_update_paths_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
if (scene == NULL) {
return OPERATOR_CANCELLED;
}
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
animviz_motionpath_compute_range(ob, scene);
/* verify that the selected object has the appropriate settings */
animviz_verify_motionpaths(op->reports, scene, ob, NULL);
}
CTX_DATA_END;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
ED_objects_recalculate_paths_selected(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
@ -1454,44 +1454,6 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Update Motion Paths Range from Scene Operator
* \{ */
static int object_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
/* Loop over all editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, editable_objects) {
/* use Preview Range or Full Frame Range - whichever is in use */
ob->avs.path_sf = PSFRA;
ob->avs.path_ef = PEFRA;
/* tag for updates */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
}
CTX_DATA_END;
return OPERATOR_FINISHED;
}
void OBJECT_OT_paths_range_update(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Update Range from Scene";
ot->idname = "OBJECT_OT_paths_range_update";
ot->description = "Update frame range for motion paths from the Scene's current frame range";
/* callbacks */
ot->exec = object_update_paths_range_exec;
ot->poll = ED_operator_object_active_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -77,7 +77,6 @@ void OBJECT_OT_shade_flat(struct wmOperatorType *ot);
void OBJECT_OT_paths_calculate(struct wmOperatorType *ot);
void OBJECT_OT_paths_update(struct wmOperatorType *ot);
void OBJECT_OT_paths_clear(struct wmOperatorType *ot);
void OBJECT_OT_paths_range_update(struct wmOperatorType *ot);
void OBJECT_OT_paths_update_visible(struct wmOperatorType *ot);
void OBJECT_OT_forcefield_toggle(struct wmOperatorType *ot);

View File

@ -46,7 +46,6 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_paths_calculate);
WM_operatortype_append(OBJECT_OT_paths_update);
WM_operatortype_append(OBJECT_OT_paths_clear);
WM_operatortype_append(OBJECT_OT_paths_range_update);
WM_operatortype_append(OBJECT_OT_paths_update_visible);
WM_operatortype_append(OBJECT_OT_forcefield_toggle);

View File

@ -110,7 +110,7 @@ static void nla_action_draw_keyframes(
*/
Range2f frame_range;
ED_keylist_frame_range(keylist, &frame_range);
ED_keylist_all_keys_frame_range(keylist, &frame_range);
immRectf(pos_id, frame_range.min, ymin + 2, frame_range.max, ymax - 2);
immUnbindProgram();

View File

@ -104,12 +104,14 @@ typedef struct bAnimVizSettings {
short path_type;
/** Number of frames between points indicated on the paths. */
short path_step;
/** #eMotionPath_Ranges. */
short path_range;
/** #eMotionPaths_ViewFlag. */
short path_viewflag;
/** #eMotionPaths_BakeFlag. */
short path_bakeflag;
char _pad[6];
char _pad[4];
/** Start and end frames of path-calculation range. */
int path_sf, path_ef;
@ -131,6 +133,14 @@ typedef enum eMotionPaths_Types {
MOTIONPATH_TYPE_ACFRA = 1,
} eMotionPath_Types;
/* bAnimVizSettings->path_range */
typedef enum eMotionPath_Ranges {
/* Default is scene */
MOTIONPATH_RANGE_SCENE = 0,
MOTIONPATH_RANGE_KEYS_SELECTED = 1,
MOTIONPATH_RANGE_KEYS_ALL = 2,
} eMotionPath_Ranges;
/* bAnimVizSettings->path_viewflag */
typedef enum eMotionPaths_ViewFlag {
/* show frames on path */

View File

@ -87,6 +87,8 @@ DEF_ENUM(rna_enum_keying_flag_items_api)
DEF_ENUM(rna_enum_fmodifier_type_items)
DEF_ENUM(rna_enum_motionpath_bake_location_items)
DEF_ENUM(rna_enum_motionpath_display_type_items)
DEF_ENUM(rna_enum_motionpath_range_items)
DEF_ENUM(rna_enum_event_value_items)
DEF_ENUM(rna_enum_event_direction_items)

View File

@ -36,6 +36,31 @@ const EnumPropertyItem rna_enum_motionpath_bake_location_items[] = {
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_motionpath_display_type_items[] = {
{MOTIONPATH_TYPE_ACFRA,
"CURRENT_FRAME",
0,
"Around Frame",
"Display Paths of poses within a fixed number of frames around the current frame"},
{MOTIONPATH_TYPE_RANGE,
"RANGE",
0,
"In Range",
"Display Paths of poses within specified range"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_motionpath_range_items[] = {
{MOTIONPATH_RANGE_KEYS_ALL, "KEYS_ALL", 0, "All Keys", "From the first keyframe to the last"},
{MOTIONPATH_RANGE_KEYS_SELECTED,
"KEYS_SELECTED",
0,
"Selected Keys",
"From the first selected keyframe to the last"},
{MOTIONPATH_RANGE_SCENE, "SCENE", 0, "Scene Frame Range", "The entire Scene / Preview range"},
{0, NULL, 0, NULL, NULL},
};
#ifdef RNA_RUNTIME
static PointerRNA rna_AnimViz_motion_paths_get(PointerRNA *ptr)
@ -173,20 +198,6 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem prop_type_items[] = {
{MOTIONPATH_TYPE_ACFRA,
"CURRENT_FRAME",
0,
"Around Frame",
"Display Paths of poses within a fixed number of frames around the current frame"},
{MOTIONPATH_TYPE_RANGE,
"RANGE",
0,
"In Range",
"Display Paths of poses within specified range"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "AnimVizMotionPaths", NULL);
RNA_def_struct_sdna(srna, "bAnimVizSettings");
RNA_def_struct_nested(brna, srna, "AnimViz");
@ -198,10 +209,16 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "path_type");
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_enum_items(prop, rna_enum_motionpath_display_type_items);
RNA_def_property_ui_text(prop, "Paths Type", "Type of range to show for Motion Paths");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
prop = RNA_def_property(srna, "range", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "path_range");
RNA_def_property_enum_items(prop, rna_enum_motionpath_range_items);
RNA_def_property_ui_text(prop, "Paths Range", "Type of range to calculate for Motion Paths");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
prop = RNA_def_property(srna, "bake_location", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "path_bakeflag");
RNA_def_property_enum_items(prop, rna_enum_motionpath_bake_location_items);