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

The Motion Paths operators are now also added to the Object context menu
and the Dopesheet context menu.

The scene range operator was removed, because the operators now
automatically find the range when baking the motion paths.

The clear operator now appears separated in "Selected Only" and "All",
because it was not clear for the user what the button was doing.

Reviewed By: sybren, looch

Maniphest Tasks: T93047

Differential Revision: https://developer.blender.org/D13687
This commit is contained in:
Colin Marmont 2022-02-28 12:23:56 +01:00 committed by Sybren A. Stüvel
parent 6f23401e98
commit 1558b270e9
Notes: blender-bot 2023-02-14 07:31:34 +01:00
Referenced by commit 7306417ae4, Revert "Animation: Sensible frame range for motion paths"
Referenced by issue #93047, Use other frame range for new motion paths instead of 1-250
18 changed files with 296 additions and 164 deletions

View File

@ -24,55 +24,55 @@ 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")
col = layout.column(align=True)
if mps.type == 'CURRENT_FRAME':
col = layout.column(align=True)
col.prop(mps, "frame_before", text="Frame Range Before")
col.prop(mps, "frame_after", text="After")
col.prop(mps, "frame_step", text="Step")
elif mps.type == 'RANGE':
col = layout.column(align=True)
col.prop(mps, "frame_start", text="Frame Range Start")
col.prop(mps, "frame_end", text="End")
col.prop(mps, "frame_step", text="Step")
col.prop(mps, "frame_step", text="Step")
# Calculation Range
col = layout.column(align=True)
row = col.row(align=True)
row.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)
row = col.row(align=True)
if bones:
col.operator("pose.paths_update", text="Update Paths", icon='BONE_DATA')
row.operator("pose.paths_update", text="Update Paths", icon='BONE_DATA')
row.operator("pose.paths_clear", text="", icon='X').only_selected = True
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').only_selected = False
else:
col.operator("object.paths_update", text="Update Paths", icon='OBJECT_DATA')
row.operator("object.paths_update", text="Update Paths", icon='OBJECT_DATA')
row.operator("object.paths_clear", text="", icon='X').only_selected = True
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').only_selected = False
else:
col = layout.column(align=True)
col.label(text="Nothing to show yet...", icon='ERROR')
col.label(text="No Motion Path generated yet", icon='ERROR')
# Don't invoke settings popup because settings are right above
col.operator_context = 'EXEC_REGION_WIN'
if bones:
col.operator("pose.paths_calculate", text="Calculate...", icon='BONE_DATA')
col.operator(
"pose.paths_calculate", text="Generate for selected bones", icon='BONE_DATA')
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')
col.operator("object.paths_calculate", text="Generate", 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').only_selected = False
class MotionPathButtonsPanel_display:

View File

@ -663,6 +663,10 @@ class DOPESHEET_MT_context_menu(Menu):
layout.operator_menu_enum("action.mirror", "type", text="Mirror")
layout.operator_menu_enum("action.snap", "type", text="Snap")
if st.mode == 'DOPESHEET':
layout.separator()
layout.menu("VIEW3D_MT_motion_path")
class DOPESHEET_MT_channel_context_menu(Menu):
bl_label = "Dope Sheet Channel Context Menu"

View File

@ -390,6 +390,9 @@ class GRAPH_MT_context_menu(Menu):
layout.operator_menu_enum("graph.mirror", "type", text="Mirror")
layout.operator_menu_enum("graph.snap", "type", text="Snap")
layout.separator()
layout.menu("VIEW3D_MT_motion_path")
class GRAPH_MT_pivot_pie(Menu):
bl_label = "Pivot Point"

View File

@ -2383,6 +2383,25 @@ class VIEW3D_MT_object_clear(Menu):
layout.operator("object.origin_clear", text="Origin")
class VIEW3D_MT_motion_path(Menu):
bl_label = "Motion Paths"
def draw(self, _context):
layout = self.layout
ob = _context.object
if ob.mode == 'OBJECT':
layout.operator("object.paths_calculate")
layout.operator("object.paths_update")
layout.operator("object.paths_update_visible")
layout.operator("object.paths_clear", text="Clear all").only_selected = False
layout.operator("object.paths_clear", text="Clear selected").only_selected = True
elif ob.mode == 'POSE':
layout.operator("pose.paths_calculate")
layout.operator("pose.paths_update")
layout.operator("pose.paths_clear", text="Clear all").only_selected = False
layout.operator("pose.paths_clear", text="Clear selected").only_selected = True
class VIEW3D_MT_object_context_menu(Menu):
bl_label = "Object Context Menu"
@ -2584,6 +2603,7 @@ class VIEW3D_MT_object_context_menu(Menu):
layout.menu("VIEW3D_MT_mirror")
layout.menu("VIEW3D_MT_snap")
layout.menu("VIEW3D_MT_object_parent")
layout.menu("VIEW3D_MT_motion_path")
layout.operator_context = 'INVOKE_REGION_WIN'
if view and view.local_view:
@ -3631,10 +3651,10 @@ class VIEW3D_MT_pose_context_menu(Menu):
layout.separator()
layout.operator("pose.paths_calculate", text="Calculate Motion Paths")
layout.operator("pose.paths_clear", text="Clear Motion Paths")
layout.operator("pose.paths_update", text="Update Armature Motion Paths")
layout.operator("object.paths_update_visible", text="Update All Motion Paths")
layout.operator("pose.paths_calculate")
layout.operator("pose.paths_update")
layout.operator("pose.paths_clear", text="Clear all").only_selected = False
layout.operator("pose.paths_clear", text="Clear selected").only_selected = True
layout.separator()
@ -7623,6 +7643,7 @@ classes = (
VIEW3D_MT_object_quick_effects,
VIEW3D_MT_object_showhide,
VIEW3D_MT_object_cleanup,
VIEW3D_MT_motion_path,
VIEW3D_MT_make_single_user,
VIEW3D_MT_make_links,
VIEW3D_MT_brush_paint_modes,

View File

@ -153,6 +153,11 @@ 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) {
/* The length might be the same, but the start and end could be different */
if (mpath->start_frame != avs->path_sf) {
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

@ -90,8 +90,8 @@ static void motion_path_get_frame_range_to_draw(bAnimVizSettings *avs,
end = current_frame + avs->path_ac + 1;
}
else {
start = avs->path_sf;
end = avs->path_ef;
start = mpath->start_frame;
end = mpath->end_frame;
}
if (start > end) {

View File

@ -340,6 +340,55 @@ static void motionpath_free_free_tree_data(ListBase *targets)
}
}
void animviz_motionpath_compute_range(Object *ob, Scene *scene)
{
struct AnimKeylist *keylist = ED_keylist_create();
bAnimVizSettings *avs;
if (ob->mode == OB_MODE_POSE) {
avs = &ob->pose->avs;
bArmature *arm = ob->data;
if (!ELEM(NULL, ob->adt, ob->adt->action, arm->adt)) {
/* Loop through all the fcurves and get only the keylists for the bone location fcurves */
LISTBASE_FOREACH (FCurve *, fcu, &ob->adt->action->curves) {
if (strstr(fcu->rna_path, "pose.bones[") && strstr(fcu->rna_path, "location")) {
fcurve_to_keylist(arm->adt, fcu, keylist, 0);
}
}
}
}
else {
avs = &ob->avs;
if (!ELEM(NULL, ob->adt, ob->adt->action)) {
/* Loop through all the fcurves and get only the keylists for the location fcurves */
LISTBASE_FOREACH (FCurve *, fcu, &ob->adt->action->curves) {
if (strcmp(fcu->rna_path, "location") == 0) {
fcurve_to_keylist(ob->adt, fcu, keylist, 0);
}
}
}
}
if (ED_keylist_is_empty(keylist) || (avs->path_range == MOTIONPATH_RANGE_SCENE)) {
/* Apply scene frame range if no keys where found or if scene range is selected */
avs->path_sf = PSFRA;
avs->path_ef = PEFRA;
}
else {
/* Compute keys range */
Range2f frame_range;
const bool only_selected = avs->path_range == MOTIONPATH_RANGE_KEYS_SELECTED;
/* Get range for all keys if selected_only is false or if no keys are selected */
if (!(only_selected && ED_keylist_selected_keys_frame_range(keylist, &frame_range))) {
ED_keylist_all_keys_frame_range(keylist, &frame_range);
}
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

@ -220,8 +220,8 @@ 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_enum_set(op->ptr, "display_type", avs->path_type);
RNA_enum_set(op->ptr, "range", avs->path_range);
RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
@ -229,7 +229,7 @@ static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEven
/* 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
@ -249,8 +249,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"));
@ -258,7 +259,6 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
/* set up path data for bones being calculated */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object) {
/* verify makes sure that the selected bone has a bone with the appropriate settings */
animviz_verify_motionpaths(op->reports, scene, ob, pchan);
}
CTX_DATA_END;
@ -281,6 +281,19 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static bool pose_calculate_paths_poll(bContext *C)
{
if (!ED_operator_posemode_exclusive(C)) {
return false;
}
Object *ob = CTX_data_active_object(C);
bArmature *arm = ob->data;
if (ELEM(NULL, ob, arm, ob->pose)) {
return false;
}
return true;
}
void POSE_OT_paths_calculate(wmOperatorType *ot)
{
/* identifiers */
@ -291,30 +304,24 @@ void POSE_OT_paths_calculate(wmOperatorType *ot)
/* api callbacks */
ot->invoke = pose_calculate_paths_invoke;
ot->exec = pose_calculate_paths_exec;
ot->poll = ED_operator_posemode_exclusive;
ot->poll = pose_calculate_paths_poll;
/* flags */
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",
@ -336,7 +343,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);
@ -344,6 +351,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

@ -1089,6 +1089,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 does 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

@ -21,6 +21,7 @@
#include "BLT_translation.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
@ -73,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"
@ -1209,30 +1211,32 @@ 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;
/* When operator is not invoked, dismiss the operator settings */
if (op->flag & OP_IS_INVOKE) {
bAnimVizSettings *avs = &ob->avs;
/* grab baking settings from operator settings */
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);
@ -1251,9 +1255,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;
@ -1264,24 +1268,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",
"");
}
/** \} */
@ -1300,13 +1298,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);
@ -1456,44 +1460,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

@ -76,7 +76,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

@ -45,7 +45,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_all_items)
DEF_ENUM(rna_enum_event_value_keymouse_items)

View File

@ -36,6 +36,27 @@ 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 range", ""},
{MOTIONPATH_RANGE_KEYS_SELECTED, "KEYS_SELECTED", 0, "Selected keys range", ""},
{MOTIONPATH_RANGE_SCENE, "SCENE", 0, "Scene frame range", ""},
{0, NULL, 0, NULL, NULL},
};
#ifdef RNA_RUNTIME
static PointerRNA rna_AnimViz_motion_paths_get(PointerRNA *ptr)
@ -173,20 +194,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 +205,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);