Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py5
-rw-r--r--source/blender/blenkernel/BKE_anim.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/intern/anim.c186
-rw-r--r--source/blender/blenkernel/intern/object.c7
-rw-r--r--source/blender/blenkernel/intern/scene.c4
-rw-r--r--source/blender/editors/transform/transform.c19
-rw-r--r--source/blender/editors/transform/transform.h7
-rw-r--r--source/blender/editors/transform/transform_conversions.c191
-rw-r--r--source/blender/makesdna/DNA_action_types.h3
-rw-r--r--source/blender/makesdna/DNA_scene_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c6
-rw-r--r--source/blender/windowmanager/WM_api.h1
13 files changed, 408 insertions, 29 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 405f2630cc4..d005b84f59d 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -113,12 +113,15 @@ class VIEW3D_HT_header(Header):
# Pose
if obj and mode == 'POSE':
+
row = layout.row(align=True)
row.operator("pose.copy", text="", icon='COPYDOWN')
row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False
row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True
-
+ if mode in {'OBJECT', 'POSE'}:
+ row.prop(toolsettings, "realtime_motion_path")
+
class VIEW3D_MT_editor_menus(Menu):
bl_space_type = 'VIEW3D_MT_editor_menus'
bl_label = ""
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
index bfba221e488..90af9a15a97 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -32,6 +32,7 @@
* \author nzc
* \since March 2001
*/
+struct bContext;
struct EvaluationContext;
struct Path;
struct Object;
@@ -63,6 +64,7 @@ struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports, struc
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
void animviz_calc_motionpaths(struct Scene *scene, ListBase *targets);
+void animviz_queue_object(const struct bContext *C, struct Object *ob);
/* ---------------------------------------------------- */
/* Curve Paths */
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 8d1fe7640ee..d134701fc80 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -210,7 +210,7 @@ void BKE_object_handle_update(struct EvaluationContext *eval_ctx, struct Scene *
void BKE_object_handle_update_ex(struct EvaluationContext *eval_ctx,
struct Scene *scene, struct Object *ob,
struct RigidBodyWorld *rbw,
- const bool do_proxy_update);
+ const bool do_proxy_update, float ctime);
void BKE_object_sculpt_modifiers_changed(struct Object *ob);
int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index b878dbe1f39..cdf05f89b8d 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -35,6 +35,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_threads.h"
#include "BLF_translation.h"
@@ -42,18 +43,24 @@
#include "DNA_armature_types.h"
#include "DNA_key_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
#include "BKE_curve.h"
+#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_main.h"
+#include "BKE_library.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_anim.h"
#include "BKE_report.h"
+#include "WM_types.h"
+#include "WM_api.h"
+
// XXX bad level call...
/* --------------------- */
@@ -84,6 +91,12 @@ void animviz_settings_init(bAnimVizSettings *avs)
avs->path_sf = 1; /* xxx - take from scene instead? */
avs->path_ef = 250; /* xxx - take from scene instead? */
+ avs->inv_start = avs->path_sf;
+ avs->inv_end = avs->path_ef;
+
+ /* max value shows invalid data */
+ avs->calc_end = avs->calc_start = INT32_MAX;
+
avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
avs->path_step = 1;
@@ -182,6 +195,11 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
else {
/* clear the existing path (as the range has changed), and reallocate below */
animviz_free_motionpath_cache(mpath);
+ avs->inv_start = avs->path_sf;
+ avs->inv_end = avs->path_ef;
+
+ /* max value shows invalid data */
+ avs->calc_end = avs->calc_start = INT32_MAX;
}
}
}
@@ -221,6 +239,7 @@ typedef struct MPathTarget {
bMotionPath *mpath; /* motion path in question */
Object *ob; /* source object */
+ Base *base_copy; /* copy object, to be used for position calculations */
bPoseChannel *pchan; /* source posechannel (if applicable) */
} MPathTarget;
@@ -288,11 +307,19 @@ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets)
baseNext = base->next;
if ((base->object == mpt->ob) && !(mpt->ob->flag & BA_TEMP_TAG)) {
+// Object *ob = BKE_object_copy(mpt->ob);
+// Base *basen = MEM_mallocN(sizeof(Base), "duplibase");
+// *basen = *base;
+// basen->object = ob;
+// mpt->base_copy = basen;
+// ob->flag |= BA_TEMP_TAG;
+
BLI_remlink(&scene->base, base);
BLI_addhead(&scene->base, base);
-
+ //BLI_addhead(&scene->base, basen);
+
mpt->ob->flag |= BA_TEMP_TAG;
-
+
/* we really don't need to continue anymore once this happens, but this line might really 'break' */
break;
}
@@ -304,7 +331,7 @@ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets)
}
/* update scene for current frame */
-static void motionpaths_calc_update_scene(Scene *scene)
+static void motionpaths_calc_update_scene(Scene *scene, float cframe)
{
#if 1 // 'production' optimizations always on
/* rigid body simulation needs complete update to work correctly for now */
@@ -325,6 +352,9 @@ static void motionpaths_calc_update_scene(Scene *scene)
for (base = scene->base.first; base; base = base->next) {
if (base->object->flag & BA_TEMP_TAG)
last = base;
+ else
+ /* no need to stay here, we got the last already */
+ break;
}
/* perform updates for tagged objects */
@@ -332,7 +362,8 @@ static void motionpaths_calc_update_scene(Scene *scene)
* is animated but not attached to/updatable from objects */
for (base = scene->base.first; base; base = base->next) {
/* update this object */
- BKE_object_handle_update(G.main->eval_ctx, scene, base->object);
+ BKE_object_handle_update_ex(G.main->eval_ctx, scene, base->object, NULL, true, cframe);
+
/* if this is the last one we need to update, let's stop to save some time */
if (base == last)
@@ -352,7 +383,7 @@ static void motionpaths_calc_update_scene(Scene *scene)
/* ........ */
/* perform baking for the targets on the current frame */
-static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
+static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
{
MPathTarget *mpt;
@@ -364,11 +395,11 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
/* current frame must be within the range the cache works for
* - is inclusive of the first frame, but not the last otherwise we get buffer overruns
*/
- if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame))
+ if ((cframe < mpath->start_frame) || (cframe >= mpath->end_frame))
continue;
/* get the relevant cache vert to write to */
- mpv = mpath->points + (CFRA - mpath->start_frame);
+ mpv = mpath->points + (cframe - mpath->start_frame);
/* pose-channel or object path baking? */
if (mpt->pchan) {
@@ -386,6 +417,7 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
else {
/* worldspace object location */
copy_v3_v3(mpv->co, mpt->ob->obmat[3]);
+ //copy_v3_v3(mpv->co, mpt->base_copy->object->obmat[3]);
}
}
}
@@ -425,17 +457,16 @@ void animviz_calc_motionpaths(Scene *scene, ListBase *targets)
motionpaths_calc_optimise_depsgraph(scene, targets);
/* calculate path over requested range */
- for (CFRA = sfra; CFRA <= efra; CFRA++) {
+ for (cfra = sfra; cfra <= efra; cfra++) {
/* update relevant data for new frame */
- motionpaths_calc_update_scene(scene);
+ motionpaths_calc_update_scene(scene, cfra);
/* perform baking for targets */
- motionpaths_calc_bake_targets(scene, targets);
+ motionpaths_calc_bake_targets(targets, cfra);
}
/* reset original environment */
- CFRA = cfra;
- motionpaths_calc_update_scene(scene);
+ motionpaths_calc_update_scene(scene, CFRA);
/* clear recalc flags from targets */
for (mpt = targets->first; mpt; mpt = mpt->next) {
@@ -449,9 +480,140 @@ void animviz_calc_motionpaths(Scene *scene, ListBase *targets)
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
+
+ /*
+ if (mpt->base_copy) {
+ DAG_id_type_tag(G.main, ID_OB);
+ DAG_relations_tag_update(G.main);
+ BKE_scene_base_unlink(scene, mpt->base_copy);
+ BKE_libblock_free_us(G.main, mpt->base_copy->object);
+ if (scene->basact == mpt->base_copy) scene->basact = NULL;
+ MEM_freeN(mpt->base_copy);
+ }
+ */
}
}
+typedef struct MotionPathJob {
+ ListBase motionpaths;
+ ThreadMutex *mutex;
+ Scene *scene;
+ int total; /* total keyframes needed for processing */
+ int processed; /* number of processed keyframes */
+} MotionPathJob;
+
+typedef struct MotionPathJobElement {
+ struct MotionPathJobElement *next, *prev;
+} MotionPathJobElement;
+
+static void free_motionpath_job(void *data)
+{
+ MotionPathJob *mpj = (MotionPathJob *)data;
+
+ BLI_mutex_free(mpj->mutex);
+ BLI_freelistN(&mpj->motionpaths);
+ MEM_freeN(mpj);
+}
+
+/* only this runs inside thread */
+static void motionpath_startjob(void *data, short *stop, short *do_update, float *progress)
+{
+ MotionPathJob *mpj = data;
+ MotionPathJobElement *mpe;
+
+ BLI_mutex_lock(mpj->mutex);
+ mpe = mpj->motionpaths.first;
+ BLI_mutex_unlock(mpj->mutex);
+
+ while (mpe) {
+ MotionPathJobElement *mpe_next;
+
+ if (*stop || G.is_break) {
+ BLI_mutex_lock(mpj->mutex);
+ mpe = mpe->next;
+ BLI_mutex_unlock(mpj->mutex);
+ while (mpe) {
+ /*
+ sound = previewjb->sound;
+
+ BLI_spin_lock(sound->spinlock);
+ sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
+ BLI_spin_unlock(sound->spinlock);
+
+ BLI_mutex_lock(pj->mutex);
+ previewjb = previewjb->next;
+ BLI_mutex_unlock(pj->mutex);
+ */
+ }
+
+ BLI_mutex_lock(mpj->mutex);
+ BLI_freelistN(&mpj->motionpaths);
+ mpj->total = 0;
+ mpj->processed = 0;
+ BLI_mutex_unlock(mpj->mutex);
+ break;
+ }
+
+ BLI_mutex_lock(mpj->mutex);
+ mpe_next = mpe->next;
+ BLI_freelinkN(&mpj->motionpaths, mpe);
+ mpe = mpe_next;
+ mpj->processed++;
+ *progress = (mpj->total > 0) ? (float)mpj->processed / (float)mpj->total : 1.0f;
+ *do_update = true;
+ BLI_mutex_unlock(mpj->mutex);
+ }
+}
+
+static void motionpath_endjob(void *data)
+{
+ MotionPathJob *mpj = data;
+
+ WM_main_add_notifier(NC_SCENE | ND_ANIMPLAY, mpj->scene);
+}
+
+
+/* add an object ot the thread calculating motionpaths */
+void animviz_queue_object(const bContext *C, struct Object *ob)
+{
+ /* first, get the preview job, if it exists */
+ wmJob *wm_job;
+ MotionPathJob *mpj;
+ ScrArea *sa = CTX_wm_area(C);
+ MotionPathJobElement *mpe = MEM_callocN(sizeof(MotionPathJobElement), "motionpath_element");
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Motion Paths",
+ WM_JOB_PROGRESS, WM_JOB_TYPE_MOTIONPATHS);
+
+ mpj = WM_jobs_customdata_get(wm_job);
+
+ if (!mpj) {
+ mpj = MEM_callocN(sizeof(MotionPathJob), "motion path job");
+
+ mpj->mutex = BLI_mutex_alloc();
+ mpj->scene = CTX_data_scene(C);
+
+ WM_jobs_customdata_set(wm_job, mpj, free_motionpath_job);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
+ WM_jobs_callbacks(wm_job, motionpath_startjob, NULL, NULL, motionpath_endjob);
+ }
+
+ /* attempt to lock mutex of job here */
+
+ //mpe-> = ;
+
+ BLI_mutex_lock(mpj->mutex);
+ BLI_addtail(&mpj->motionpaths, mpe);
+ mpj->total++;
+ BLI_mutex_unlock(mpj->mutex);
+
+ if (!WM_jobs_is_running(wm_job)) {
+ G.is_break = false;
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ }
+}
+
+
+
/* ******************************************************************** */
/* Curve Paths - for curve deforms and/or curve following */
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 365a5d838eb..04bdfe3b58e 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -3071,7 +3071,8 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
Scene *scene, Object *ob,
RigidBodyWorld *rbw,
- const bool do_proxy_update)
+ const bool do_proxy_update,
+ float ctime)
{
if (ob->recalc & OB_RECALC_ALL) {
/* speed optimization for animation lookups */
@@ -3117,7 +3118,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
copy_m4_m4(ob->obmat, ob->proxy_from->obmat);
}
else
- BKE_object_where_is_calc_ex(scene, rbw, ob, NULL);
+ BKE_object_where_is_calc_time_ex(scene, ob, ctime, rbw, NULL);
}
if (ob->recalc & OB_RECALC_DATA) {
@@ -3149,7 +3150,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
*/
void BKE_object_handle_update(EvaluationContext *eval_ctx, Scene *scene, Object *ob)
{
- BKE_object_handle_update_ex(eval_ctx, scene, ob, NULL, true);
+ BKE_object_handle_update_ex(eval_ctx, scene, ob, NULL, true, BKE_scene_frame_get(scene));
}
void BKE_object_sculpt_modifiers_changed(Object *ob)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index bd923d296f1..b6fede75d96 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1378,7 +1378,7 @@ static void scene_update_all_bases(EvaluationContext *eval_ctx, Scene *scene, Sc
for (base = scene->base.first; base; base = base->next) {
Object *object = base->object;
- BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, true);
+ BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, true, BKE_scene_frame_get(scene_parent));
if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, object, object->dup_group);
@@ -1429,7 +1429,7 @@ static void scene_update_object_func(TaskPool *pool, void *taskdata, int threadi
* separately from main thread because of we've got no idea about
* dependencies inside the group.
*/
- BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, false);
+ BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, false, BKE_scene_frame_get(scene_parent));
/* Calculate statistics. */
if (add_to_stats) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 34314e7ff3d..38fb35bbb1a 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -66,6 +66,7 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "ED_armature.h"
#include "ED_image.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
@@ -2391,6 +2392,24 @@ void transformApply(bContext *C, TransInfo *t)
viewRedrawForce(C, t);
}
+ if (t->scene->toolsettings->realtime_motion_path) {
+ if ((t->flag & T_POSE) && (t->poseobj) && (t->mode != TFM_DUMMY)) {
+ if ((t->poseobj->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
+ //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
+ bool targetless_ik = (t->flag & T_AUTOIK) != 0; // XXX this currently doesn't work, since flags aren't set yet!
+
+ autokeyframe_pose_cb_func(C, t->scene, (View3D *)t->view, t->poseobj, t->mode, targetless_ik);
+ }
+ }
+ else {
+ int i;
+ for (i = 0; i < t->total; i++) {
+ TransData *td = t->data + i;
+ autokeyframe_ob_cb_func(C, t->scene, (View3D *)t->view, td->ob, t->mode);
+ }
+ }
+ }
+
/* If auto confirm is on, break after one pass */
if (t->options & CTX_AUTOCONFIRM) {
t->state = TRANS_CONFIRM;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 2672df24d2e..33b4e2b5448 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -592,8 +592,13 @@ bool transdata_check_local_islands(TransInfo *t, short around);
int count_set_pose_transflags(int *out_mode, short around, struct Object *ob);
/* auto-keying stuff used by special_aftertrans_update */
+void autokeyframe_ob_tag_existing(struct Scene *scene, struct Object *ob);
+void autokeyframe_ob_revert(struct bContext *C, struct Scene *scene, struct Object *ob);
void autokeyframe_ob_cb_func(struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode);
-void autokeyframe_pose_cb_func(struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode, short targetless_ik);
+
+void autokeyframe_pose_tag_existing(struct Scene *scene, struct Object *ob);
+void autokeyframe_pose_revert(struct bContext *C, struct Scene *scene, struct Object *ob, bool targetless_ik);
+void autokeyframe_pose_cb_func(struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode, bool targetless_ik);
/*********************** Constraints *****************************/
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 307fa86a56b..aa0d86e5b3f 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -1066,6 +1066,9 @@ static void createTransPose(TransInfo *t, Object *ob)
/* initialize initial auto=ik chainlen's? */
if (ik_on) transform_autoik_update(t, 0);
+
+ if (t->scene->toolsettings->realtime_motion_path)
+ autokeyframe_pose_tag_existing(t->scene, ob);
}
void restoreBones(TransInfo *t)
@@ -5505,6 +5508,10 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
unit_m3(td->smtx);
unit_m3(td->mtx);
}
+
+ if (t->scene->toolsettings->realtime_motion_path) {
+ autokeyframe_ob_tag_existing(scene, ob);
+ }
}
@@ -5685,6 +5692,69 @@ static void clear_trans_object_base_flags(TransInfo *t)
/* auto-keyframing feature - for objects
* tmode: should be a transform mode
*/
+
+/* auto keyframing: we need to tag the existing fcurves before attempting to insert keyframes
+ * to avoid deleting them by mistake. Algorithm here is that if keyframe existed before,
+ * we insert old value on cancel, else we completely delete it */
+void autokeyframe_ob_tag_existing(Scene *scene, Object *ob) {
+ ID *id = &ob->id;
+ AnimData *adt = ob->adt;
+ bAction *act = (adt) ? adt->action : NULL;
+ FCurve *fcu;
+ float cfra = (float)CFRA;
+
+ if (act) {
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ bool replace;
+ binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &replace);
+
+ fcu->flag &= ~FCURVE_TAGGED;
+ if (replace) {
+ fcu->flag |= FCURVE_TAGGED;
+ }
+ }
+ }
+ }
+}
+
+void autokeyframe_ob_revert(bContext *C, Scene *scene, Object *ob) {
+ ID *id = &ob->id;
+ AnimData *adt = ob->adt;
+ bAction *act = (adt) ? adt->action : NULL;
+ FCurve *fcu, *fcu_next;
+ ReportList *reports = CTX_wm_reports(C);
+ float cfra = (float)CFRA;
+ short flag = 0;
+
+ /* flag is initialized 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
+ * (for quick animation recording)
+ */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu_next) {
+ fcu_next = fcu->next;
+
+ if (fcu->flag & FCURVE_TAGGED) {
+ fcu->flag &= ~FCURVE_TAGGED;
+ insert_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
+ }
+ else
+ delete_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
+ }
+ }
+
+ if (C && (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
+ //ED_objects_clear_paths(C); // XXX for now, don't need to clear
+ ED_objects_recalculate_paths(C, scene);
+ }
+ }
+}
+
// NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode)
{
@@ -5717,7 +5787,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
/* only key on available channels */
if (adt && adt->action) {
for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
- fcu->flag &= ~FCURVE_SELECTED;
+ fcu->flag &= ~FCURVE_SELECTED;
insert_keyframe(reports, id, adt->action,
(fcu->grp ? fcu->grp->name : NULL),
fcu->rna_path, fcu->array_index, cfra, flag);
@@ -5795,12 +5865,112 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
}
}
+/* auto keyframing: we need to tag the existing fcurves before attempting to insert keyframes
+ * to avoid deleting them by mistake. Algorithm here is that if keyframe existed before,
+ * we insert old value on cancel, else we completely delete it */
+void autokeyframe_pose_tag_existing(Scene *scene, Object *ob) {
+ ID *id = &ob->id;
+ AnimData *adt = ob->adt;
+ bAction *act = (adt) ? adt->action : NULL;
+ bPose *pose = ob->pose;
+ bPoseChannel *pchan;
+ FCurve *fcu;
+ float cfra = (float)CFRA;
+
+ if (act) {
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* only insert keyframes for this F-Curve if it affects the current bone */
+ if (strstr(fcu->rna_path, "bones")) {
+ char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+
+ /* only if bone name matches too...
+ * NOTE: this will do constraints too, but those are ok to do here too?
+ */
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ bool replace;
+ binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &replace);
+
+ fcu->flag &= ~FCURVE_TAGGED;
+ if (replace) {
+ fcu->flag |= FCURVE_TAGGED;
+ }
+ }
+ if (pchanName) MEM_freeN(pchanName);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void autokeyframe_pose_revert(bContext *C, Scene *scene, Object *ob, bool targetless_ik) {
+ ID *id = &ob->id;
+ AnimData *adt = ob->adt;
+ bAction *act = (adt) ? adt->action : NULL;
+ bPose *pose = ob->pose;
+ bPoseChannel *pchan;
+ FCurve *fcu, *fcu_next;
+ ReportList *reports = CTX_wm_reports(C);
+ float cfra = (float)CFRA;
+ short flag = 0;
+
+ /* flag is initialized 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
+ * (for quick animation recording)
+ */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ if (targetless_ik)
+ flag |= INSERTKEY_MATRIX;
+
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu_next) {
+ fcu_next = fcu->next;
+
+ /* only insert keyframes for this F-Curve if it affects the current bone */
+ if (strstr(fcu->rna_path, "bones")) {
+ char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+
+ /* only if bone name matches too...
+ * NOTE: this will do constraints too, but those are ok to do here too?
+ */
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ if (fcu->flag & FCURVE_TAGGED) {
+ fcu->flag &= ~FCURVE_TAGGED;
+ insert_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
+ }
+ else
+ delete_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
+ }
+ if (pchanName) MEM_freeN(pchanName);
+ }
+ }
+ }
+ }
+ }
+
+ if (C && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
+ //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
+ ED_pose_recalculate_paths(scene, ob);
+ }
+ }
+}
+
/* auto-keyframing feature - for poses/pose-channels
* tmode: should be a transform mode
* targetless_ik: has targetless ik been done on any channels?
*/
// NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
-void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode, short targetless_ik)
+void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode, bool targetless_ik)
{
ID *id = &ob->id;
AnimData *adt = ob->adt;
@@ -5852,9 +6022,9 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
/* only if bone name matches too...
* NOTE: this will do constraints too, but those are ok to do here too?
*/
- if (pchanName && STREQ(pchanName, pchan->name))
+ if (pchanName && STREQ(pchanName, pchan->name)) {
insert_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
-
+ }
if (pchanName) MEM_freeN(pchanName);
}
}
@@ -6432,8 +6602,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
pose_grab_with_ik_clear(ob);
/* automatic inserting of keys and unkeyed tagging - only if transform wasn't canceled (or TFM_DUMMY) */
- if (!canceled && (t->mode != TFM_DUMMY)) {
- autokeyframe_pose_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
+ if (t->mode != TFM_DUMMY) {
+ if (t->scene->toolsettings->realtime_motion_path && canceled)
+ autokeyframe_pose_revert(C, t->scene, ob, targetless_ik);
+ else {
+ autokeyframe_pose_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
+ }
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else if (arm->flag & ARM_DELAYDEFORM) {
@@ -6498,9 +6672,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
/* Set autokey if necessary */
- if (!canceled) {
+ if (t->scene->toolsettings->realtime_motion_path && canceled)
+ autokeyframe_ob_revert(C, t->scene, ob);
+ else
autokeyframe_ob_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode);
- }
/* restore rigid body transform */
if (ob->rigidbody_object && canceled) {
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index b8688e5e12a..5e076136f9b 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -113,6 +113,9 @@ typedef struct bAnimVizSettings {
int path_sf, path_ef; /* start and end frames of path-calculation range */
int path_bc, path_ac; /* number of frames before/after current frame to show */
+
+ int calc_start, calc_end; /* frames around which we have calculated motionpaths already */
+ int inv_start, inv_end; /* start of invalid frames in the motionpath */
} bAnimVizSettings;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 94b609e9b9f..1872ced9b24 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1262,7 +1262,9 @@ typedef struct ToolSettings {
/* Multires */
char multires_subdiv_type;
- char pad3[1];
+
+ /* Motion Paths update in real time */
+ char realtime_motion_path;
/* Skeleton generation */
short skgen_resolution;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 4a05a56b37a..810d83a8ddf 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2152,6 +2152,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Relaxation Method", "Algorithm used for UV relaxation");
/* Transform */
+ prop = RNA_def_property(srna, "realtime_motion_path", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "realtime_motion_path", 1);
+ RNA_def_property_ui_text(prop, "Real-Time Motion Path",
+ "Update motion paths in real time while tranfrorming");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
prop = RNA_def_property(srna, "proportional_edit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "proportional");
RNA_def_property_enum_items(prop, proportional_editing_items);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index eea28ca3146..c08a17396aa 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -427,6 +427,7 @@ enum {
WM_JOB_TYPE_CLIP_PREFETCH,
WM_JOB_TYPE_SEQ_BUILD_PROXY,
WM_JOB_TYPE_SEQ_BUILD_PREVIEW,
+ WM_JOB_TYPE_MOTIONPATHS,
/* add as needed, screencast, seq proxy build
* if having hard coded values is a problem */
};