Cleanup: Move each special_aftertrans_update to their respective TransData file
This commit is contained in:
parent
63a40ed422
commit
46e0ec05ef
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@
|
||||
#define __TRANSFORM_CONVERT_H__
|
||||
|
||||
struct BezTriple;
|
||||
struct FCurve;
|
||||
struct ListBase;
|
||||
struct Object;
|
||||
struct TransData;
|
||||
@ -37,20 +38,7 @@ struct bKinematicConstraint;
|
||||
struct bPoseChannel;
|
||||
|
||||
/* transform_convert.c */
|
||||
int transform_convert_pose_transflags_update(Object *ob,
|
||||
const int mode,
|
||||
const short around,
|
||||
bool has_translate_rotate[2]);
|
||||
void transform_autoik_update(TransInfo *t, short mode);
|
||||
void autokeyframe_object(struct bContext *C,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer,
|
||||
struct Object *ob,
|
||||
int tmode);
|
||||
void autokeyframe_pose(
|
||||
struct bContext *C, struct Scene *scene, struct Object *ob, int tmode, short targetless_ik);
|
||||
bool motionpath_need_update_object(struct Scene *scene, struct Object *ob);
|
||||
bool motionpath_need_update_pose(struct Scene *scene, struct Object *ob);
|
||||
int special_transform_moving(TransInfo *t);
|
||||
void special_aftertrans_update(struct bContext *C, TransInfo *t);
|
||||
void sort_trans_data_dist(TransInfo *t);
|
||||
@ -97,7 +85,7 @@ typedef enum eTransConvertType {
|
||||
/* transform_convert.c */
|
||||
bool transform_mode_use_local_origins(const TransInfo *t);
|
||||
void transform_around_single_fallback(TransInfo *t);
|
||||
void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
|
||||
void posttrans_fcurve_clean(struct FCurve *fcu, const int sel_flag, const bool use_handle);
|
||||
bool constraints_list_needinv(TransInfo *t, ListBase *list);
|
||||
void calc_distanceCurveVerts(TransData *head, TransData *tail);
|
||||
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
|
||||
@ -109,13 +97,18 @@ void animrecord_check_state(TransInfo *t, struct Object *ob);
|
||||
/* transform_convert_action.c */
|
||||
void createTransActionData(bContext *C, TransInfo *t);
|
||||
void recalcData_actedit(TransInfo *t);
|
||||
void special_aftertrans_update__actedit(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_armature.c */
|
||||
struct bKinematicConstraint *has_targetless_ik(struct bPoseChannel *pchan);
|
||||
int transform_convert_pose_transflags_update(Object *ob,
|
||||
const int mode,
|
||||
const short around,
|
||||
bool has_translate_rotate[2]);
|
||||
void createTransPose(TransInfo *t);
|
||||
void createTransArmatureVerts(TransInfo *t);
|
||||
void recalcData_edit_armature(TransInfo *t);
|
||||
void recalcData_pose(TransInfo *t);
|
||||
void special_aftertrans_update__pose(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_cursor.c */
|
||||
void createTransCursor_image(TransInfo *t);
|
||||
@ -128,6 +121,7 @@ void recalcData_curve(TransInfo *t);
|
||||
/* transform_convert_graph.c */
|
||||
void createTransGraphEditData(bContext *C, TransInfo *t);
|
||||
void recalcData_graphedit(TransInfo *t);
|
||||
void special_aftertrans_update__graph(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_gpencil.c */
|
||||
void createTransGPencil(bContext *C, TransInfo *t);
|
||||
@ -140,6 +134,7 @@ void recalcData_lattice(TransInfo *t);
|
||||
/* transform_convert_mask.c */
|
||||
void createTransMaskingData(bContext *C, TransInfo *t);
|
||||
void recalcData_mask_common(TransInfo *t);
|
||||
void special_aftertrans_update__mask(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_mball.c */
|
||||
void createTransMBallVerts(TransInfo *t);
|
||||
@ -147,6 +142,7 @@ void createTransMBallVerts(TransInfo *t);
|
||||
/* transform_convert_mesh.c */
|
||||
void createTransEditVerts(TransInfo *t);
|
||||
void recalcData_mesh(TransInfo *t);
|
||||
void special_aftertrans_update__mesh(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_mesh_edge.c */
|
||||
void createTransEdge(TransInfo *t);
|
||||
@ -158,16 +154,18 @@ void recalcData_uv(TransInfo *t);
|
||||
/* transform_convert_nla.c */
|
||||
void createTransNlaData(bContext *C, TransInfo *t);
|
||||
void recalcData_nla(TransInfo *t);
|
||||
void special_aftertrans_update__nla(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_node.c */
|
||||
void createTransNodeData(TransInfo *t);
|
||||
void flushTransNodes(TransInfo *t);
|
||||
void special_aftertrans_update__node(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_object.c */
|
||||
void clear_trans_object_base_flags(TransInfo *t);
|
||||
void createTransObject(bContext *C, TransInfo *t);
|
||||
void createTransTexspace(TransInfo *t);
|
||||
void recalcData_objects(TransInfo *t);
|
||||
void special_aftertrans_update__object(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_paintcurve.c */
|
||||
void createTransPaintCurveVerts(bContext *C, TransInfo *t);
|
||||
@ -184,9 +182,10 @@ void recalcData_sculpt(TransInfo *t);
|
||||
/* transform_convert_sequencer.c */
|
||||
void createTransSeqData(TransInfo *t);
|
||||
void recalcData_sequencer(TransInfo *t);
|
||||
void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_tracking.c */
|
||||
void createTransTrackingData(bContext *C, TransInfo *t);
|
||||
void cancelTransTracking(TransInfo *t);
|
||||
void recalcData_tracking(TransInfo *t);
|
||||
void special_aftertrans_update__movieclip(bContext *C, TransInfo *t);
|
||||
#endif
|
||||
|
@ -27,14 +27,23 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rect.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_mask.h"
|
||||
#include "BKE_nla.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_keyframes_edit.h"
|
||||
#include "ED_markers.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_convert.h"
|
||||
@ -619,3 +628,297 @@ void recalcData_actedit(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Action
|
||||
* \{ */
|
||||
|
||||
static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
|
||||
{
|
||||
const MaskLayerShape *frame_a = a;
|
||||
const MaskLayerShape *frame_b = b;
|
||||
|
||||
if (frame_a->frame < frame_b->frame) {
|
||||
return -1;
|
||||
}
|
||||
if (frame_a->frame > frame_b->frame) {
|
||||
return 1;
|
||||
}
|
||||
*((bool *)thunk) = true;
|
||||
/* selected last */
|
||||
if ((frame_a->flag & MASK_SHAPE_SELECT) && ((frame_b->flag & MASK_SHAPE_SELECT) == 0)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void posttrans_mask_clean(Mask *mask)
|
||||
{
|
||||
MaskLayer *masklay;
|
||||
|
||||
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
|
||||
MaskLayerShape *masklay_shape, *masklay_shape_next;
|
||||
bool is_double = false;
|
||||
|
||||
BLI_listbase_sort_r(&masklay->splines_shapes, masklay_shape_cmp_frame, &is_double);
|
||||
|
||||
if (is_double) {
|
||||
for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
|
||||
masklay_shape = masklay_shape_next) {
|
||||
masklay_shape_next = masklay_shape->next;
|
||||
if (masklay_shape_next && masklay_shape->frame == masklay_shape_next->frame) {
|
||||
BKE_mask_layer_shape_unlink(masklay, masklay_shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
|
||||
masklay_shape = masklay_shape->next) {
|
||||
BLI_assert(!masklay_shape->next || masklay_shape->frame < masklay_shape->next->frame);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
WM_main_add_notifier(NC_MASK | NA_EDITED, mask);
|
||||
}
|
||||
|
||||
/* Called by special_aftertrans_update to make sure selected gp-frames replace
|
||||
* any other gp-frames which may reside on that frame (that are not selected).
|
||||
* It also makes sure gp-frames are still stored in chronological order after
|
||||
* transform.
|
||||
*/
|
||||
static void posttrans_gpd_clean(bGPdata *gpd)
|
||||
{
|
||||
bGPDlayer *gpl;
|
||||
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
bGPDframe *gpf, *gpfn;
|
||||
bool is_double = false;
|
||||
|
||||
BKE_gpencil_layer_frames_sort(gpl, &is_double);
|
||||
|
||||
if (is_double) {
|
||||
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
|
||||
gpfn = gpf->next;
|
||||
if (gpfn && gpf->framenum == gpfn->framenum) {
|
||||
BKE_gpencil_layer_frame_delete(gpl, gpf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
|
||||
BLI_assert(!gpf->next || gpf->framenum < gpf->next->framenum);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* set cache flag to dirty */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
|
||||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, gpd);
|
||||
}
|
||||
|
||||
/* Called by special_aftertrans_update to make sure selected keyframes replace
|
||||
* any other keyframes which may reside on that frame (that is not selected).
|
||||
* remake_action_ipos should have already been called
|
||||
*/
|
||||
static void posttrans_action_clean(bAnimContext *ac, bAction *act)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
bAnimListElem *ale;
|
||||
int filter;
|
||||
|
||||
/* filter data */
|
||||
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
|
||||
ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
|
||||
|
||||
/* loop through relevant data, removing keyframes as appropriate
|
||||
* - all keyframes are converted in/out of global time
|
||||
*/
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
||||
|
||||
if (adt) {
|
||||
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
|
||||
posttrans_fcurve_clean(ale->key_data, SELECT, false); /* only use handles in graph editor */
|
||||
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
|
||||
}
|
||||
else {
|
||||
posttrans_fcurve_clean(ale->key_data, SELECT, false); /* only use handles in graph editor */
|
||||
}
|
||||
}
|
||||
|
||||
/* free temp data */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
|
||||
{
|
||||
SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
|
||||
bAnimContext ac;
|
||||
|
||||
const bool canceled = (t->state == TRANS_CANCEL);
|
||||
const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
|
||||
|
||||
/* initialize relevant anim-context 'context' data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object *ob = ac.obact;
|
||||
|
||||
if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) {
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
bAnimListElem *ale;
|
||||
short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
|
||||
|
||||
/* get channels to work on */
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
/* these should all be F-Curves */
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
|
||||
/* 3 cases here for curve cleanups:
|
||||
* 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
|
||||
* 2) canceled == 0 -> user confirmed the transform,
|
||||
* so duplicates should be removed
|
||||
* 3) canceled + duplicate -> user canceled the transform,
|
||||
* but we made duplicates, so get rid of these
|
||||
*/
|
||||
if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
|
||||
if (adt) {
|
||||
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
|
||||
posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
|
||||
ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
|
||||
}
|
||||
else {
|
||||
posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free temp memory */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
else if (ac.datatype == ANIMCONT_ACTION) { // TODO: just integrate into the above...
|
||||
/* Depending on the lock status, draw necessary views */
|
||||
// fixme... some of this stuff is not good
|
||||
if (ob) {
|
||||
if (ob->pose || BKE_key_from_object(ob)) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
}
|
||||
else {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
|
||||
}
|
||||
}
|
||||
|
||||
/* 3 cases here for curve cleanups:
|
||||
* 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
|
||||
* 2) canceled == 0 -> user confirmed the transform,
|
||||
* so duplicates should be removed.
|
||||
* 3) canceled + duplicate -> user canceled the transform,
|
||||
* but we made duplicates, so get rid of these.
|
||||
*/
|
||||
if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
|
||||
posttrans_action_clean(&ac, (bAction *)ac.data);
|
||||
}
|
||||
}
|
||||
else if (ac.datatype == ANIMCONT_GPENCIL) {
|
||||
/* remove duplicate frames and also make sure points are in order! */
|
||||
/* 3 cases here for curve cleanups:
|
||||
* 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
|
||||
* 2) canceled == 0 -> user confirmed the transform,
|
||||
* so duplicates should be removed
|
||||
* 3) canceled + duplicate -> user canceled the transform,
|
||||
* but we made duplicates, so get rid of these
|
||||
*/
|
||||
if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
const int filter = ANIMFILTER_DATA_VISIBLE;
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
if (ale->datatype == ALE_GPFRAME) {
|
||||
ale->id->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
if (ale->datatype == ALE_GPFRAME) {
|
||||
if (ale->id->tag & LIB_TAG_DOIT) {
|
||||
ale->id->tag &= ~LIB_TAG_DOIT;
|
||||
posttrans_gpd_clean((bGPdata *)ale->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
}
|
||||
else if (ac.datatype == ANIMCONT_MASK) {
|
||||
/* remove duplicate frames and also make sure points are in order! */
|
||||
/* 3 cases here for curve cleanups:
|
||||
* 1) NOTRANSKEYCULL on:
|
||||
* Cleanup of duplicates shouldn't be done.
|
||||
* 2) canceled == 0:
|
||||
* User confirmed the transform, so duplicates should be removed.
|
||||
* 3) Canceled + duplicate:
|
||||
* User canceled the transform, but we made duplicates, so get rid of these.
|
||||
*/
|
||||
if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
const int filter = ANIMFILTER_DATA_VISIBLE;
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
if (ale->datatype == ALE_MASKLAY) {
|
||||
ale->id->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
if (ale->datatype == ALE_MASKLAY) {
|
||||
if (ale->id->tag & LIB_TAG_DOIT) {
|
||||
ale->id->tag &= ~LIB_TAG_DOIT;
|
||||
posttrans_mask_clean((Mask *)ale->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
}
|
||||
|
||||
/* marker transform, not especially nice but we may want to move markers
|
||||
* at the same time as keyframes in the dope sheet.
|
||||
*/
|
||||
if ((saction->flag & SACTION_MARKERS_MOVE) && (canceled == 0)) {
|
||||
if (t->mode == TFM_TIME_TRANSLATE) {
|
||||
#if 0
|
||||
if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */
|
||||
/* same as below */
|
||||
ED_markers_post_apply_transform(
|
||||
ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
|
||||
}
|
||||
else /* TFM_TIME_TRANSLATE */
|
||||
#endif
|
||||
{
|
||||
ED_markers_post_apply_transform(
|
||||
ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
|
||||
}
|
||||
}
|
||||
else if (t->mode == TFM_TIME_SCALE) {
|
||||
ED_markers_post_apply_transform(
|
||||
ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure all F-Curves are set correctly */
|
||||
if (!ELEM(ac.datatype, ANIMCONT_GPENCIL)) {
|
||||
ANIM_editkeyframes_refresh(&ac);
|
||||
}
|
||||
|
||||
/* clear flag that was set for time-slide drawing */
|
||||
saction->flag &= ~SACTION_MOVING;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -29,8 +29,10 @@
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_context.h"
|
||||
@ -45,6 +47,8 @@
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_snap.h"
|
||||
|
||||
@ -63,6 +67,183 @@ typedef struct BoneInitData {
|
||||
float zwidth;
|
||||
} BoneInitData;
|
||||
|
||||
/* Return if we need to update motion paths, only if they already exist,
|
||||
* and we will insert a keyframe at the end of transform. */
|
||||
static bool motionpath_need_update_pose(Scene *scene, Object *ob)
|
||||
{
|
||||
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
|
||||
return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-keyframing feature - for poses/pose-channels
|
||||
*
|
||||
* \param tmode: 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.
|
||||
*/
|
||||
static void autokeyframe_pose(
|
||||
bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
ID *id = &ob->id;
|
||||
AnimData *adt = ob->adt;
|
||||
bAction *act = (adt) ? adt->action : NULL;
|
||||
bPose *pose = ob->pose;
|
||||
bPoseChannel *pchan;
|
||||
FCurve *fcu;
|
||||
|
||||
// TODO: this should probably be done per channel instead...
|
||||
if (!autokeyframe_cfra_can_key(scene, id)) {
|
||||
/* tag channels that should have unkeyed data */
|
||||
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if (pchan->bone->flag & BONE_TRANSFORM) {
|
||||
/* tag this channel */
|
||||
pchan->bone->flag |= BONE_UNKEYED;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
|
||||
ListBase nla_cache = {NULL, NULL};
|
||||
float cfra = (float)CFRA;
|
||||
eInsertKeyFlags 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, true);
|
||||
|
||||
if (targetless_ik) {
|
||||
flag |= INSERTKEY_MATRIX;
|
||||
}
|
||||
|
||||
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if ((pchan->bone->flag & BONE_TRANSFORM) == 0 &&
|
||||
!((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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? */
|
||||
if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
|
||||
/* run the active Keying Set on the current datasource */
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
/* only insert into available channels? */
|
||||
else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
|
||||
if (act) {
|
||||
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") == NULL) {
|
||||
continue;
|
||||
}
|
||||
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)) {
|
||||
insert_keyframe(bmain,
|
||||
reports,
|
||||
id,
|
||||
act,
|
||||
((fcu->grp) ? (fcu->grp->name) : (NULL)),
|
||||
fcu->rna_path,
|
||||
fcu->array_index,
|
||||
cfra,
|
||||
ts->keyframe_type,
|
||||
&nla_cache,
|
||||
flag);
|
||||
}
|
||||
|
||||
if (pchanName) {
|
||||
MEM_freeN(pchanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* only insert keyframe if needed? */
|
||||
else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
|
||||
bool do_loc = false, do_rot = false, do_scale = false;
|
||||
|
||||
/* Filter the conditions when this happens
|
||||
* (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
|
||||
if (tmode == TFM_TRANSLATION) {
|
||||
if (targetless_ik) {
|
||||
do_rot = true;
|
||||
}
|
||||
else {
|
||||
do_loc = true;
|
||||
}
|
||||
}
|
||||
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
|
||||
if (ELEM(scene->toolsettings->transform_pivot_point,
|
||||
V3D_AROUND_CURSOR,
|
||||
V3D_AROUND_ACTIVE)) {
|
||||
do_loc = true;
|
||||
}
|
||||
|
||||
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
|
||||
do_rot = true;
|
||||
}
|
||||
}
|
||||
else if (tmode == TFM_RESIZE) {
|
||||
if (ELEM(scene->toolsettings->transform_pivot_point,
|
||||
V3D_AROUND_CURSOR,
|
||||
V3D_AROUND_ACTIVE)) {
|
||||
do_loc = true;
|
||||
}
|
||||
|
||||
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
|
||||
do_scale = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_loc) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
if (do_rot) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
if (do_scale) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
|
||||
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, ANIM_KS_LOC_ROT_SCALE_ID);
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
|
||||
/* free temp info */
|
||||
BLI_freelistN(&dsources);
|
||||
}
|
||||
|
||||
BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
|
||||
}
|
||||
|
||||
static bConstraint *add_temporary_ik_constraint(bPoseChannel *pchan,
|
||||
bKinematicConstraint *targetless_con)
|
||||
{
|
||||
@ -94,173 +275,11 @@ static void update_deg_with_temporary_ik(Main *bmain, Object *ob)
|
||||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
static void add_pose_transdata(
|
||||
TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
|
||||
{
|
||||
Bone *bone = pchan->bone;
|
||||
float pmat[3][3], omat[3][3];
|
||||
float cmat[3][3], tmat[3][3];
|
||||
float vec[3];
|
||||
|
||||
copy_v3_v3(vec, pchan->pose_mat[3]);
|
||||
copy_v3_v3(td->center, vec);
|
||||
|
||||
td->ob = ob;
|
||||
td->flag = TD_SELECTED;
|
||||
if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
|
||||
td->flag |= TD_NOCENTER;
|
||||
}
|
||||
|
||||
if (bone->flag & BONE_TRANSFORM_CHILD) {
|
||||
td->flag |= TD_NOCENTER;
|
||||
td->flag |= TD_NO_LOC;
|
||||
}
|
||||
|
||||
td->extra = pchan;
|
||||
td->protectflag = pchan->protectflag;
|
||||
|
||||
td->loc = pchan->loc;
|
||||
copy_v3_v3(td->iloc, pchan->loc);
|
||||
|
||||
td->ext->size = pchan->size;
|
||||
copy_v3_v3(td->ext->isize, pchan->size);
|
||||
|
||||
if (pchan->rotmode > 0) {
|
||||
td->ext->rot = pchan->eul;
|
||||
td->ext->rotAxis = NULL;
|
||||
td->ext->rotAngle = NULL;
|
||||
td->ext->quat = NULL;
|
||||
|
||||
copy_v3_v3(td->ext->irot, pchan->eul);
|
||||
}
|
||||
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
|
||||
td->ext->rot = NULL;
|
||||
td->ext->rotAxis = pchan->rotAxis;
|
||||
td->ext->rotAngle = &pchan->rotAngle;
|
||||
td->ext->quat = NULL;
|
||||
|
||||
td->ext->irotAngle = pchan->rotAngle;
|
||||
copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
|
||||
}
|
||||
else {
|
||||
td->ext->rot = NULL;
|
||||
td->ext->rotAxis = NULL;
|
||||
td->ext->rotAngle = NULL;
|
||||
td->ext->quat = pchan->quat;
|
||||
|
||||
copy_qt_qt(td->ext->iquat, pchan->quat);
|
||||
}
|
||||
td->ext->rotOrder = pchan->rotmode;
|
||||
|
||||
/* proper way to get parent transform + own transform + constraints transform */
|
||||
copy_m3_m4(omat, ob->obmat);
|
||||
|
||||
/* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */
|
||||
{
|
||||
BoneParentTransform bpt;
|
||||
float rpmat[3][3];
|
||||
|
||||
BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
|
||||
if (t->mode == TFM_TRANSLATION) {
|
||||
copy_m3_m4(pmat, bpt.loc_mat);
|
||||
}
|
||||
else {
|
||||
copy_m3_m4(pmat, bpt.rotscale_mat);
|
||||
}
|
||||
|
||||
/* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal,
|
||||
* and want align snapping, we just need both loc_mat and rotscale_mat.
|
||||
* So simply always store rotscale mat in td->ext, and always use it to apply rotations...
|
||||
* Ugly to need such hacks! :/ */
|
||||
copy_m3_m4(rpmat, bpt.rotscale_mat);
|
||||
|
||||
if (constraints_list_needinv(t, &pchan->constraints)) {
|
||||
copy_m3_m4(tmat, pchan->constinv);
|
||||
invert_m3_m3(cmat, tmat);
|
||||
mul_m3_series(td->mtx, cmat, omat, pmat);
|
||||
mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
|
||||
}
|
||||
else {
|
||||
mul_m3_series(td->mtx, omat, pmat);
|
||||
mul_m3_series(td->ext->r_mtx, omat, rpmat);
|
||||
}
|
||||
invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
|
||||
}
|
||||
|
||||
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
|
||||
|
||||
/* exceptional case: rotate the pose bone which also applies transformation
|
||||
* when a parentless bone has BONE_NO_LOCAL_LOCATION [] */
|
||||
if (!ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) &&
|
||||
(pchan->bone->flag & BONE_NO_LOCAL_LOCATION)) {
|
||||
if (pchan->parent) {
|
||||
/* same as td->smtx but without pchan->bone->bone_mat */
|
||||
td->flag |= TD_PBONE_LOCAL_MTX_C;
|
||||
mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
|
||||
}
|
||||
else {
|
||||
td->flag |= TD_PBONE_LOCAL_MTX_P;
|
||||
}
|
||||
}
|
||||
|
||||
/* for axismat we use bone's own transform */
|
||||
copy_m3_m4(pmat, pchan->pose_mat);
|
||||
mul_m3_m3m3(td->axismtx, omat, pmat);
|
||||
normalize_m3(td->axismtx);
|
||||
|
||||
if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
|
||||
bArmature *arm = tc->poseobj->data;
|
||||
|
||||
if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
|
||||
td->loc = NULL;
|
||||
td->val = &bone->dist;
|
||||
td->ival = bone->dist;
|
||||
}
|
||||
else {
|
||||
// abusive storage of scale in the loc pointer :)
|
||||
td->loc = &bone->xwidth;
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
td->val = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* in this case we can do target-less IK grabbing */
|
||||
if (t->mode == TFM_TRANSLATION) {
|
||||
bKinematicConstraint *data = has_targetless_ik(pchan);
|
||||
if (data) {
|
||||
if (data->flag & CONSTRAINT_IK_TIP) {
|
||||
copy_v3_v3(data->grabtarget, pchan->pose_tail);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(data->grabtarget, pchan->pose_head);
|
||||
}
|
||||
td->loc = data->grabtarget;
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
|
||||
data->flag |= CONSTRAINT_IK_AUTO;
|
||||
|
||||
/* Add a temporary auto IK constraint here, as we will only temporarily active this
|
||||
* targetless bone during transform. (Targetless IK constraints are treated as if they are
|
||||
* disabled unless they are transformed). */
|
||||
add_temporary_ik_constraint(pchan, data);
|
||||
Main *bmain = CTX_data_main(t->context);
|
||||
update_deg_with_temporary_ik(bmain, ob);
|
||||
|
||||
/* only object matrix correction */
|
||||
copy_m3_m3(td->mtx, omat);
|
||||
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
/* store reference to first constraint */
|
||||
td->con = pchan->constraints.first;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Pose Auto-IK
|
||||
* \{ */
|
||||
|
||||
bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
|
||||
static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
|
||||
{
|
||||
bConstraint *con = pchan->constraints.first;
|
||||
|
||||
@ -528,34 +547,174 @@ static void pose_mirror_info_init(PoseInitData_Mirror *pid,
|
||||
}
|
||||
}
|
||||
|
||||
static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
|
||||
{
|
||||
bPoseChannel *pchan = pid->pchan;
|
||||
copy_v3_v3(pchan->loc, pid->orig.loc);
|
||||
copy_v3_v3(pchan->size, pid->orig.size);
|
||||
pchan->curve_in_x = pid->orig.curve_in_x;
|
||||
pchan->curve_out_x = pid->orig.curve_out_x;
|
||||
pchan->roll1 = pid->orig.roll1;
|
||||
pchan->roll2 = pid->orig.roll2;
|
||||
|
||||
if (pchan->rotmode > 0) {
|
||||
copy_v3_v3(pchan->eul, pid->orig.eul);
|
||||
}
|
||||
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
|
||||
copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle);
|
||||
pchan->rotAngle = pid->orig.axis_angle[3];
|
||||
}
|
||||
else {
|
||||
copy_qt_qt(pchan->quat, pid->orig.quat);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Convert Armature
|
||||
* \{ */
|
||||
|
||||
static void add_pose_transdata(
|
||||
TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
|
||||
{
|
||||
Bone *bone = pchan->bone;
|
||||
float pmat[3][3], omat[3][3];
|
||||
float cmat[3][3], tmat[3][3];
|
||||
float vec[3];
|
||||
|
||||
copy_v3_v3(vec, pchan->pose_mat[3]);
|
||||
copy_v3_v3(td->center, vec);
|
||||
|
||||
td->ob = ob;
|
||||
td->flag = TD_SELECTED;
|
||||
if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
|
||||
td->flag |= TD_NOCENTER;
|
||||
}
|
||||
|
||||
if (bone->flag & BONE_TRANSFORM_CHILD) {
|
||||
td->flag |= TD_NOCENTER;
|
||||
td->flag |= TD_NO_LOC;
|
||||
}
|
||||
|
||||
td->extra = pchan;
|
||||
td->protectflag = pchan->protectflag;
|
||||
|
||||
td->loc = pchan->loc;
|
||||
copy_v3_v3(td->iloc, pchan->loc);
|
||||
|
||||
td->ext->size = pchan->size;
|
||||
copy_v3_v3(td->ext->isize, pchan->size);
|
||||
|
||||
if (pchan->rotmode > 0) {
|
||||
td->ext->rot = pchan->eul;
|
||||
td->ext->rotAxis = NULL;
|
||||
td->ext->rotAngle = NULL;
|
||||
td->ext->quat = NULL;
|
||||
|
||||
copy_v3_v3(td->ext->irot, pchan->eul);
|
||||
}
|
||||
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
|
||||
td->ext->rot = NULL;
|
||||
td->ext->rotAxis = pchan->rotAxis;
|
||||
td->ext->rotAngle = &pchan->rotAngle;
|
||||
td->ext->quat = NULL;
|
||||
|
||||
td->ext->irotAngle = pchan->rotAngle;
|
||||
copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
|
||||
}
|
||||
else {
|
||||
td->ext->rot = NULL;
|
||||
td->ext->rotAxis = NULL;
|
||||
td->ext->rotAngle = NULL;
|
||||
td->ext->quat = pchan->quat;
|
||||
|
||||
copy_qt_qt(td->ext->iquat, pchan->quat);
|
||||
}
|
||||
td->ext->rotOrder = pchan->rotmode;
|
||||
|
||||
/* proper way to get parent transform + own transform + constraints transform */
|
||||
copy_m3_m4(omat, ob->obmat);
|
||||
|
||||
/* New code, using "generic" BKE_bone_parent_transform_calc_from_pchan(). */
|
||||
{
|
||||
BoneParentTransform bpt;
|
||||
float rpmat[3][3];
|
||||
|
||||
BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
|
||||
if (t->mode == TFM_TRANSLATION) {
|
||||
copy_m3_m4(pmat, bpt.loc_mat);
|
||||
}
|
||||
else {
|
||||
copy_m3_m4(pmat, bpt.rotscale_mat);
|
||||
}
|
||||
|
||||
/* Grrr! Exceptional case: When translating pose bones that are either Hinge or NoLocal,
|
||||
* and want align snapping, we just need both loc_mat and rotscale_mat.
|
||||
* So simply always store rotscale mat in td->ext, and always use it to apply rotations...
|
||||
* Ugly to need such hacks! :/ */
|
||||
copy_m3_m4(rpmat, bpt.rotscale_mat);
|
||||
|
||||
if (constraints_list_needinv(t, &pchan->constraints)) {
|
||||
copy_m3_m4(tmat, pchan->constinv);
|
||||
invert_m3_m3(cmat, tmat);
|
||||
mul_m3_series(td->mtx, cmat, omat, pmat);
|
||||
mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
|
||||
}
|
||||
else {
|
||||
mul_m3_series(td->mtx, omat, pmat);
|
||||
mul_m3_series(td->ext->r_mtx, omat, rpmat);
|
||||
}
|
||||
invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
|
||||
}
|
||||
|
||||
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
|
||||
|
||||
/* exceptional case: rotate the pose bone which also applies transformation
|
||||
* when a parentless bone has BONE_NO_LOCAL_LOCATION [] */
|
||||
if (!ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) &&
|
||||
(pchan->bone->flag & BONE_NO_LOCAL_LOCATION)) {
|
||||
if (pchan->parent) {
|
||||
/* same as td->smtx but without pchan->bone->bone_mat */
|
||||
td->flag |= TD_PBONE_LOCAL_MTX_C;
|
||||
mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
|
||||
}
|
||||
else {
|
||||
td->flag |= TD_PBONE_LOCAL_MTX_P;
|
||||
}
|
||||
}
|
||||
|
||||
/* for axismat we use bone's own transform */
|
||||
copy_m3_m4(pmat, pchan->pose_mat);
|
||||
mul_m3_m3m3(td->axismtx, omat, pmat);
|
||||
normalize_m3(td->axismtx);
|
||||
|
||||
if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
|
||||
bArmature *arm = tc->poseobj->data;
|
||||
|
||||
if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
|
||||
td->loc = NULL;
|
||||
td->val = &bone->dist;
|
||||
td->ival = bone->dist;
|
||||
}
|
||||
else {
|
||||
// abusive storage of scale in the loc pointer :)
|
||||
td->loc = &bone->xwidth;
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
td->val = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* in this case we can do target-less IK grabbing */
|
||||
if (t->mode == TFM_TRANSLATION) {
|
||||
bKinematicConstraint *data = has_targetless_ik(pchan);
|
||||
if (data) {
|
||||
if (data->flag & CONSTRAINT_IK_TIP) {
|
||||
copy_v3_v3(data->grabtarget, pchan->pose_tail);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(data->grabtarget, pchan->pose_head);
|
||||
}
|
||||
td->loc = data->grabtarget;
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
|
||||
data->flag |= CONSTRAINT_IK_AUTO;
|
||||
|
||||
/* Add a temporary auto IK constraint here, as we will only temporarily active this
|
||||
* targetless bone during transform. (Targetless IK constraints are treated as if they are
|
||||
* disabled unless they are transformed). */
|
||||
add_temporary_ik_constraint(pchan, data);
|
||||
Main *bmain = CTX_data_main(t->context);
|
||||
update_deg_with_temporary_ik(bmain, ob);
|
||||
|
||||
/* only object matrix correction */
|
||||
copy_m3_m3(td->mtx, omat);
|
||||
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
/* store reference to first constraint */
|
||||
td->con = pchan->constraints.first;
|
||||
}
|
||||
|
||||
/**
|
||||
* When objects array is NULL, use 't->data_container' as is.
|
||||
*/
|
||||
@ -1203,6 +1362,28 @@ static void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, O
|
||||
}
|
||||
}
|
||||
|
||||
static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
|
||||
{
|
||||
bPoseChannel *pchan = pid->pchan;
|
||||
copy_v3_v3(pchan->loc, pid->orig.loc);
|
||||
copy_v3_v3(pchan->size, pid->orig.size);
|
||||
pchan->curve_in_x = pid->orig.curve_in_x;
|
||||
pchan->curve_out_x = pid->orig.curve_out_x;
|
||||
pchan->roll1 = pid->orig.roll1;
|
||||
pchan->roll2 = pid->orig.roll2;
|
||||
|
||||
if (pchan->rotmode > 0) {
|
||||
copy_v3_v3(pchan->eul, pid->orig.eul);
|
||||
}
|
||||
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
|
||||
copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle);
|
||||
pchan->rotAngle = pid->orig.axis_angle[3];
|
||||
}
|
||||
else {
|
||||
copy_qt_qt(pchan->quat, pid->orig.quat);
|
||||
}
|
||||
}
|
||||
|
||||
static void restoreMirrorPoseBones(TransDataContainer *tc)
|
||||
{
|
||||
bPose *pose = tc->poseobj->pose;
|
||||
@ -1296,3 +1477,314 @@ void recalcData_pose(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Pose
|
||||
* \{ */
|
||||
|
||||
static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
|
||||
{
|
||||
Bone *bone = lb->first;
|
||||
|
||||
for (; bone; bone = bone->next) {
|
||||
if ((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED)) {
|
||||
bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
|
||||
}
|
||||
else if ((bone->flag & BONE_TRANSFORM) && (mode == TFM_ROTATION || mode == TFM_TRACKBALL) &&
|
||||
(around == V3D_AROUND_LOCAL_ORIGINS)) {
|
||||
bone->flag |= BONE_TRANSFORM_CHILD;
|
||||
}
|
||||
else {
|
||||
bone->flag &= ~BONE_TRANSFORM;
|
||||
}
|
||||
|
||||
bone_children_clear_transflag(mode, around, &bone->childbase);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sets transform flags in the bones.
|
||||
* Returns total number of bones with `BONE_TRANSFORM`. */
|
||||
int transform_convert_pose_transflags_update(Object *ob,
|
||||
const int mode,
|
||||
const short around,
|
||||
bool has_translate_rotate[2])
|
||||
{
|
||||
bArmature *arm = ob->data;
|
||||
bPoseChannel *pchan;
|
||||
Bone *bone;
|
||||
int total = 0;
|
||||
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
bone = pchan->bone;
|
||||
if (PBONE_VISIBLE(arm, bone)) {
|
||||
if ((bone->flag & BONE_SELECTED)) {
|
||||
bone->flag |= BONE_TRANSFORM;
|
||||
}
|
||||
else {
|
||||
bone->flag &= ~BONE_TRANSFORM;
|
||||
}
|
||||
|
||||
bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
|
||||
bone->flag &= ~BONE_TRANSFORM_CHILD;
|
||||
}
|
||||
else {
|
||||
bone->flag &= ~BONE_TRANSFORM;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure no bone can be transformed when a parent is transformed */
|
||||
/* since pchans are depsgraph sorted, the parents are in beginning of list */
|
||||
if (!ELEM(mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
bone = pchan->bone;
|
||||
if (bone->flag & BONE_TRANSFORM) {
|
||||
bone_children_clear_transflag(mode, around, &bone->childbase);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* now count, and check if we have autoIK or have to switch from translate to rotate */
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
bone = pchan->bone;
|
||||
if (bone->flag & BONE_TRANSFORM) {
|
||||
total++;
|
||||
|
||||
if (has_translate_rotate != NULL) {
|
||||
if (has_targetless_ik(pchan) == NULL) {
|
||||
if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
|
||||
if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
|
||||
has_translate_rotate[0] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
|
||||
has_translate_rotate[0] = true;
|
||||
}
|
||||
}
|
||||
if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
|
||||
has_translate_rotate[1] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
has_translate_rotate[0] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static short apply_targetless_ik(Object *ob)
|
||||
{
|
||||
bPoseChannel *pchan, *parchan, *chanlist[256];
|
||||
bKinematicConstraint *data;
|
||||
int segcount, apply = 0;
|
||||
|
||||
/* now we got a difficult situation... we have to find the
|
||||
* target-less IK pchans, and apply transformation to the all
|
||||
* pchans that were in the chain */
|
||||
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
data = has_targetless_ik(pchan);
|
||||
if (data && (data->flag & CONSTRAINT_IK_AUTO)) {
|
||||
|
||||
/* fill the array with the bones of the chain (armature.c does same, keep it synced) */
|
||||
segcount = 0;
|
||||
|
||||
/* exclude tip from chain? */
|
||||
if (!(data->flag & CONSTRAINT_IK_TIP)) {
|
||||
parchan = pchan->parent;
|
||||
}
|
||||
else {
|
||||
parchan = pchan;
|
||||
}
|
||||
|
||||
/* Find the chain's root & count the segments needed */
|
||||
for (; parchan; parchan = parchan->parent) {
|
||||
chanlist[segcount] = parchan;
|
||||
segcount++;
|
||||
|
||||
if (segcount == data->rootbone || segcount > 255) {
|
||||
break; // 255 is weak
|
||||
}
|
||||
}
|
||||
for (; segcount; segcount--) {
|
||||
Bone *bone;
|
||||
float mat[4][4];
|
||||
|
||||
/* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
|
||||
/* we put in channel the entire result of mat = (channel * constraint * IK) */
|
||||
/* pose_mat(b) = pose_mat(b-1) * offs_bone * mat */
|
||||
/* mat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
|
||||
|
||||
parchan = chanlist[segcount - 1];
|
||||
bone = parchan->bone;
|
||||
bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
|
||||
|
||||
BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, mat);
|
||||
/* apply and decompose, doesn't work for constraints or non-uniform scale well */
|
||||
{
|
||||
float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
|
||||
|
||||
copy_m3_m4(rmat3, mat);
|
||||
/* Make sure that our rotation matrix only contains rotation and not scale. */
|
||||
normalize_m3(rmat3);
|
||||
|
||||
/* rotation */
|
||||
/* [#22409] is partially caused by this, as slight numeric error introduced during
|
||||
* the solving process leads to locked-axis values changing. However, we cannot modify
|
||||
* the values here, or else there are huge discrepancies between IK-solver (interactive)
|
||||
* and applied poses. */
|
||||
BKE_pchan_mat3_to_rot(parchan, rmat3, false);
|
||||
|
||||
/* for size, remove rotation */
|
||||
/* causes problems with some constraints (so apply only if needed) */
|
||||
if (data->flag & CONSTRAINT_IK_STRETCH) {
|
||||
BKE_pchan_rot_to_mat3(parchan, qrmat);
|
||||
invert_m3_m3(imat3, qrmat);
|
||||
mul_m3_m3m3(smat, rmat3, imat3);
|
||||
mat3_to_size(parchan->size, smat);
|
||||
}
|
||||
|
||||
/* causes problems with some constraints (e.g. childof), so disable this */
|
||||
/* as it is IK shouldn't affect location directly */
|
||||
/* copy_v3_v3(parchan->loc, mat[3]); */
|
||||
}
|
||||
}
|
||||
|
||||
apply = 1;
|
||||
data->flag &= ~CONSTRAINT_IK_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
return apply;
|
||||
}
|
||||
|
||||
/* frees temporal IKs */
|
||||
static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
|
||||
{
|
||||
bKinematicConstraint *data;
|
||||
bPoseChannel *pchan;
|
||||
bConstraint *con, *next;
|
||||
bool relations_changed = false;
|
||||
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
/* clear all temporary lock flags */
|
||||
pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP | BONE_IK_NO_YDOF_TEMP | BONE_IK_NO_ZDOF_TEMP);
|
||||
|
||||
pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET);
|
||||
|
||||
/* remove all temporary IK-constraints added */
|
||||
for (con = pchan->constraints.first; con; con = next) {
|
||||
next = con->next;
|
||||
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
|
||||
data = con->data;
|
||||
if (data->flag & CONSTRAINT_IK_TEMP) {
|
||||
relations_changed = true;
|
||||
|
||||
/* iTaSC needs clear for removed constraints */
|
||||
BIK_clear_data(ob->pose);
|
||||
|
||||
BLI_remlink(&pchan->constraints, con);
|
||||
MEM_freeN(con->data);
|
||||
MEM_freeN(con);
|
||||
continue;
|
||||
}
|
||||
pchan->constflag |= PCHAN_HAS_IK;
|
||||
if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0)) {
|
||||
pchan->constflag |= PCHAN_HAS_TARGET;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (relations_changed) {
|
||||
/* TODO(sergey): Consider doing partial update only. */
|
||||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
}
|
||||
|
||||
void special_aftertrans_update__pose(bContext *C, TransInfo *t)
|
||||
{
|
||||
Object *ob;
|
||||
|
||||
if (t->mode == TFM_BONESIZE) {
|
||||
/* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
|
||||
* in pose mode (to use bone orientation matrix),
|
||||
* in that case we don't do operations like auto-keyframing. */
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
ob = tc->poseobj;
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const bool canceled = (t->state == TRANS_CANCEL);
|
||||
GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
|
||||
bPoseChannel *pchan;
|
||||
short targetless_ik = 0;
|
||||
|
||||
ob = tc->poseobj;
|
||||
|
||||
if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
|
||||
/* when running transform non-interactively (operator exec),
|
||||
* we need to update the pose otherwise no updates get called during
|
||||
* transform and the auto-ik is not applied. see [#26164] */
|
||||
struct Object *pose_ob = tc->poseobj;
|
||||
BKE_pose_where_is(t->depsgraph, t->scene, pose_ob);
|
||||
}
|
||||
|
||||
/* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
|
||||
if (!canceled && (t->mode != TFM_DUMMY)) {
|
||||
transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL);
|
||||
}
|
||||
|
||||
/* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
|
||||
if (!canceled && t->mode == TFM_TRANSLATION) {
|
||||
targetless_ik = apply_targetless_ik(ob);
|
||||
}
|
||||
else {
|
||||
/* not forget to clear the auto flag */
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
bKinematicConstraint *data = has_targetless_ik(pchan);
|
||||
if (data) {
|
||||
data->flag &= ~CONSTRAINT_IK_AUTO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (t->mode == TFM_TRANSLATION) {
|
||||
struct Main *bmain = CTX_data_main(t->context);
|
||||
pose_grab_with_ik_clear(bmain, 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(C, t->scene, ob, t->mode, targetless_ik);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
else {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
if (t->mode != TFM_DUMMY && motionpath_need_update_pose(t->scene, ob)) {
|
||||
BLI_gset_insert(motionpath_updates, ob);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update motion paths once for all transformed bones in an object. */
|
||||
GSetIterator gs_iter;
|
||||
GSET_ITER (gs_iter, motionpath_updates) {
|
||||
const ePosePathCalcRange range = canceled ? POSE_PATH_CALC_RANGE_CURRENT_FRAME :
|
||||
POSE_PATH_CALC_RANGE_CHANGED;
|
||||
ob = BLI_gsetIterator_getKey(&gs_iter);
|
||||
ED_pose_recalculate_paths(C, t->scene, ob, range);
|
||||
}
|
||||
BLI_gset_free(motionpath_updates, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_keyframes_edit.h"
|
||||
#include "ED_markers.h"
|
||||
|
||||
#include "UI_view2d.h"
|
||||
@ -751,6 +752,213 @@ static void flushTransGraphData(TransInfo *t)
|
||||
}
|
||||
}
|
||||
|
||||
/* struct for use in re-sorting BezTriples during Graph Editor transform */
|
||||
typedef struct BeztMap {
|
||||
BezTriple *bezt;
|
||||
uint oldIndex; /* index of bezt in fcu->bezt array before sorting */
|
||||
uint newIndex; /* index of bezt in fcu->bezt array after sorting */
|
||||
short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
|
||||
char pipo, cipo; /* interpolation of current and next segments */
|
||||
} BeztMap;
|
||||
|
||||
/* This function converts an FCurve's BezTriple array to a BeztMap array
|
||||
* NOTE: this allocates memory that will need to get freed later
|
||||
*/
|
||||
static BeztMap *bezt_to_beztmaps(BezTriple *bezts, int totvert)
|
||||
{
|
||||
BezTriple *bezt = bezts;
|
||||
BezTriple *prevbezt = NULL;
|
||||
BeztMap *bezm, *bezms;
|
||||
int i;
|
||||
|
||||
/* allocate memory for this array */
|
||||
if (totvert == 0 || bezts == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
bezm = bezms = MEM_callocN(sizeof(BeztMap) * totvert, "BeztMaps");
|
||||
|
||||
/* assign beztriples to beztmaps */
|
||||
for (i = 0; i < totvert; i++, bezm++, prevbezt = bezt, bezt++) {
|
||||
bezm->bezt = bezt;
|
||||
|
||||
bezm->oldIndex = i;
|
||||
bezm->newIndex = i;
|
||||
|
||||
bezm->pipo = (prevbezt) ? prevbezt->ipo : bezt->ipo;
|
||||
bezm->cipo = bezt->ipo;
|
||||
}
|
||||
|
||||
return bezms;
|
||||
}
|
||||
|
||||
/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
|
||||
static void sort_time_beztmaps(BeztMap *bezms, int totvert)
|
||||
{
|
||||
BeztMap *bezm;
|
||||
int i, ok = 1;
|
||||
|
||||
/* keep repeating the process until nothing is out of place anymore */
|
||||
while (ok) {
|
||||
ok = 0;
|
||||
|
||||
bezm = bezms;
|
||||
i = totvert;
|
||||
while (i--) {
|
||||
/* is current bezm out of order (i.e. occurs later than next)? */
|
||||
if (i > 0) {
|
||||
if (bezm->bezt->vec[1][0] > (bezm + 1)->bezt->vec[1][0]) {
|
||||
bezm->newIndex++;
|
||||
(bezm + 1)->newIndex--;
|
||||
|
||||
SWAP(BeztMap, *bezm, *(bezm + 1));
|
||||
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* do we need to check if the handles need to be swapped?
|
||||
* optimization: this only needs to be performed in the first loop
|
||||
*/
|
||||
if (bezm->swapHs == 0) {
|
||||
if ((bezm->bezt->vec[0][0] > bezm->bezt->vec[1][0]) &&
|
||||
(bezm->bezt->vec[2][0] < bezm->bezt->vec[1][0])) {
|
||||
/* handles need to be swapped */
|
||||
bezm->swapHs = 1;
|
||||
}
|
||||
else {
|
||||
/* handles need to be cleared */
|
||||
bezm->swapHs = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bezm++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This function firstly adjusts the pointers that the transdata has to each BezTriple */
|
||||
static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert)
|
||||
{
|
||||
BezTriple *bezts = fcu->bezt;
|
||||
BeztMap *bezm;
|
||||
TransData2D *td2d;
|
||||
TransData *td;
|
||||
int i, j;
|
||||
char *adjusted;
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
/* dynamically allocate an array of chars to mark whether an TransData's
|
||||
* pointers have been fixed already, so that we don't override ones that are
|
||||
* already done
|
||||
*/
|
||||
adjusted = MEM_callocN(tc->data_len, "beztmap_adjusted_map");
|
||||
|
||||
/* for each beztmap item, find if it is used anywhere */
|
||||
bezm = bezms;
|
||||
for (i = 0; i < totvert; i++, bezm++) {
|
||||
/* loop through transdata, testing if we have a hit
|
||||
* for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
|
||||
*/
|
||||
td2d = tc->data_2d;
|
||||
td = tc->data;
|
||||
for (j = 0; j < tc->data_len; j++, td2d++, td++) {
|
||||
/* skip item if already marked */
|
||||
if (adjusted[j] != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* update all transdata pointers, no need to check for selections etc,
|
||||
* since only points that are really needed were created as transdata
|
||||
*/
|
||||
if (td2d->loc2d == bezm->bezt->vec[0]) {
|
||||
if (bezm->swapHs == 1) {
|
||||
td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
|
||||
}
|
||||
else {
|
||||
td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
|
||||
}
|
||||
adjusted[j] = 1;
|
||||
}
|
||||
else if (td2d->loc2d == bezm->bezt->vec[2]) {
|
||||
if (bezm->swapHs == 1) {
|
||||
td2d->loc2d = (bezts + bezm->newIndex)->vec[0];
|
||||
}
|
||||
else {
|
||||
td2d->loc2d = (bezts + bezm->newIndex)->vec[2];
|
||||
}
|
||||
adjusted[j] = 1;
|
||||
}
|
||||
else if (td2d->loc2d == bezm->bezt->vec[1]) {
|
||||
td2d->loc2d = (bezts + bezm->newIndex)->vec[1];
|
||||
|
||||
/* if only control point is selected, the handle pointers need to be updated as well */
|
||||
if (td2d->h1) {
|
||||
td2d->h1 = (bezts + bezm->newIndex)->vec[0];
|
||||
}
|
||||
if (td2d->h2) {
|
||||
td2d->h2 = (bezts + bezm->newIndex)->vec[2];
|
||||
}
|
||||
|
||||
adjusted[j] = 1;
|
||||
}
|
||||
|
||||
/* the handle type pointer has to be updated too */
|
||||
if (adjusted[j] && td->flag & TD_BEZTRIPLE && td->hdata) {
|
||||
if (bezm->swapHs == 1) {
|
||||
td->hdata->h1 = &(bezts + bezm->newIndex)->h2;
|
||||
td->hdata->h2 = &(bezts + bezm->newIndex)->h1;
|
||||
}
|
||||
else {
|
||||
td->hdata->h1 = &(bezts + bezm->newIndex)->h1;
|
||||
td->hdata->h2 = &(bezts + bezm->newIndex)->h2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free temp memory used for 'adjusted' array */
|
||||
MEM_freeN(adjusted);
|
||||
}
|
||||
|
||||
/* This function is called by recalcData during the Transform loop to recalculate
|
||||
* the handles of curves and sort the keyframes so that the curves draw correctly.
|
||||
* It is only called if some keyframes have moved out of order.
|
||||
*
|
||||
* anim_data is the list of channels (F-Curves) retrieved already containing the
|
||||
* channels to work on. It should not be freed here as it may still need to be used.
|
||||
*/
|
||||
static void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
|
||||
{
|
||||
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
|
||||
bAnimListElem *ale;
|
||||
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
|
||||
|
||||
/* sort and reassign verts */
|
||||
for (ale = anim_data->first; ale; ale = ale->next) {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
|
||||
if (fcu->bezt) {
|
||||
BeztMap *bezm;
|
||||
|
||||
/* adjust transform-data pointers */
|
||||
/* note, none of these functions use 'use_handle', it could be removed */
|
||||
bezm = bezt_to_beztmaps(fcu->bezt, fcu->totvert);
|
||||
sort_time_beztmaps(bezm, fcu->totvert);
|
||||
beztmap_to_data(t, fcu, bezm, fcu->totvert);
|
||||
|
||||
/* free mapping stuff */
|
||||
MEM_freeN(bezm);
|
||||
|
||||
/* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
|
||||
sort_time_fcurve(fcu);
|
||||
|
||||
/* make sure handles are all set correctly */
|
||||
testhandles_fcurve(fcu, BEZT_FLAG_TEMP_TAG, use_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* helper for recalcData() - for Graph Editor transforms */
|
||||
void recalcData_graphedit(TransInfo *t)
|
||||
{
|
||||
@ -820,3 +1028,68 @@ void recalcData_graphedit(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Graph
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__graph(bContext *C, TransInfo *t)
|
||||
{
|
||||
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
|
||||
bAnimContext ac;
|
||||
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
|
||||
|
||||
const bool canceled = (t->state == TRANS_CANCEL);
|
||||
const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
|
||||
|
||||
/* initialize relevant anim-context 'context' data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ac.datatype) {
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
bAnimListElem *ale;
|
||||
short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
|
||||
|
||||
/* get channels to work on */
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
|
||||
/* 3 cases here for curve cleanups:
|
||||
* 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
|
||||
* 2) canceled == 0 -> user confirmed the transform,
|
||||
* so duplicates should be removed
|
||||
* 3) canceled + duplicate -> user canceled the transform,
|
||||
* but we made duplicates, so get rid of these
|
||||
*/
|
||||
if ((sipo->flag & SIPO_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
|
||||
if (adt) {
|
||||
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
|
||||
posttrans_fcurve_clean(fcu, BEZT_FLAG_TEMP_TAG, use_handle);
|
||||
ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
|
||||
}
|
||||
else {
|
||||
posttrans_fcurve_clean(fcu, BEZT_FLAG_TEMP_TAG, use_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free temp memory */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
/* Make sure all F-Curves are set correctly, but not if transform was
|
||||
* canceled, since then curves were already restored to initial state.
|
||||
* Note: if the refresh is really needed after cancel then some way
|
||||
* has to be added to not update handle types (see bug 22289).
|
||||
*/
|
||||
if (!canceled) {
|
||||
ANIM_editkeyframes_refresh(&ac);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -33,8 +33,13 @@
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "ED_clip.h"
|
||||
#include "ED_image.h"
|
||||
#include "ED_keyframing.h"
|
||||
#include "ED_mask.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_convert.h"
|
||||
|
||||
@ -449,3 +454,45 @@ void recalcData_mask_common(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Mask
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__mask(bContext *C, TransInfo *t)
|
||||
{
|
||||
Mask *mask = NULL;
|
||||
|
||||
if (t->spacetype == SPACE_CLIP) {
|
||||
SpaceClip *sc = t->area->spacedata.first;
|
||||
mask = ED_space_clip_get_mask(sc);
|
||||
}
|
||||
else if (t->spacetype == SPACE_IMAGE) {
|
||||
SpaceImage *sima = t->area->spacedata.first;
|
||||
mask = ED_space_image_get_mask(sima);
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
if (t->scene->nodetree) {
|
||||
/* tracks can be used for stabilization nodes,
|
||||
* flush update for such nodes */
|
||||
// if (nodeUpdateID(t->scene->nodetree, &mask->id))
|
||||
{
|
||||
WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO - dont key all masks... */
|
||||
if (IS_AUTOKEY_ON(t->scene)) {
|
||||
Scene *scene = t->scene;
|
||||
|
||||
if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) {
|
||||
WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
|
||||
DEG_id_tag_update(&mask->id, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -1402,3 +1402,71 @@ void recalcData_mesh(TransInfo *t)
|
||||
}
|
||||
}
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Mesh
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
|
||||
{
|
||||
const bool canceled = (t->state == TRANS_CANCEL);
|
||||
if (t->mode == TFM_EDGE_SLIDE) {
|
||||
/* handle multires re-projection, done
|
||||
* on transform completion since it's
|
||||
* really slow -joeedh */
|
||||
projectEdgeSlideData(t, !canceled);
|
||||
}
|
||||
else if (t->mode == TFM_VERT_SLIDE) {
|
||||
/* as above */
|
||||
projectVertSlideData(t, !canceled);
|
||||
}
|
||||
|
||||
bool use_automerge = !canceled && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
|
||||
if (use_automerge) {
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
|
||||
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
|
||||
BMesh *bm = em->bm;
|
||||
char hflag;
|
||||
bool has_face_sel = (bm->totfacesel != 0);
|
||||
|
||||
if (tc->use_mirror_axis_any) {
|
||||
/* Rather then adjusting the selection (which the user would notice)
|
||||
* tag all mirrored verts, then auto-merge those. */
|
||||
BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
|
||||
|
||||
TransDataMirror *td_mirror = tc->data_mirror;
|
||||
for (int i = tc->data_mirror_len; i--; td_mirror++) {
|
||||
BM_elem_flag_enable((BMVert *)td_mirror->extra, BM_ELEM_TAG);
|
||||
}
|
||||
|
||||
hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
|
||||
}
|
||||
else {
|
||||
hflag = BM_ELEM_SELECT;
|
||||
}
|
||||
|
||||
if (t->flag & T_AUTOSPLIT) {
|
||||
EDBM_automerge_and_split(
|
||||
tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
|
||||
}
|
||||
else {
|
||||
EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
|
||||
}
|
||||
|
||||
/* Special case, this is needed or faces won't re-select.
|
||||
* Flush selected edges to faces. */
|
||||
if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
|
||||
EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
/* table needs to be created for each edit command, since vertices can move etc */
|
||||
ED_mesh_mirror_spatial_table_end(tc->obedit);
|
||||
/* TODO(campbell): xform: We need support for many mirror objects at once! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/** \} */
|
||||
|
@ -36,6 +36,8 @@
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_markers.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "transform.h"
|
||||
@ -513,3 +515,44 @@ void recalcData_nla(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform NLA
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t))
|
||||
{
|
||||
bAnimContext ac;
|
||||
|
||||
/* initialize relevant anim-context 'context' data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ac.datatype) {
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
bAnimListElem *ale;
|
||||
short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
|
||||
|
||||
/* get channels to work on */
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
NlaTrack *nlt = (NlaTrack *)ale->data;
|
||||
|
||||
/* make sure strips are in order again */
|
||||
BKE_nlatrack_sort_strips(nlt);
|
||||
|
||||
/* remove the temp metas */
|
||||
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
|
||||
}
|
||||
|
||||
/* free temp memory */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
|
||||
/* perform after-transfrom validation */
|
||||
ED_nla_postop_refresh(&ac);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -194,3 +194,39 @@ void flushTransNodes(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Node
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__node(bContext *C, TransInfo *t)
|
||||
{
|
||||
struct Main *bmain = CTX_data_main(C);
|
||||
const bool canceled = (t->state == TRANS_CANCEL);
|
||||
|
||||
SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
|
||||
if (canceled && t->remove_on_cancel) {
|
||||
/* remove selected nodes on cancel */
|
||||
bNodeTree *ntree = snode->edittree;
|
||||
if (ntree) {
|
||||
bNode *node, *node_next;
|
||||
for (node = ntree->nodes.first; node; node = node_next) {
|
||||
node_next = node->next;
|
||||
if (node->flag & NODE_SELECT) {
|
||||
nodeRemoveNode(bmain, ntree, node, true);
|
||||
}
|
||||
}
|
||||
ntreeUpdateTree(bmain, ntree);
|
||||
}
|
||||
}
|
||||
|
||||
if (!canceled) {
|
||||
ED_node_post_apply_transform(C, snode->edittree);
|
||||
ED_node_link_insert(bmain, t->area);
|
||||
}
|
||||
|
||||
/* clear link line */
|
||||
ED_node_link_intersect_test(t->area, 0);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -30,10 +30,12 @@
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_pointcache.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_rigidbody.h"
|
||||
#include "BKE_scene.h"
|
||||
@ -466,7 +468,7 @@ static int count_proportional_objects(TransInfo *t)
|
||||
return total;
|
||||
}
|
||||
|
||||
void clear_trans_object_base_flags(TransInfo *t)
|
||||
static void clear_trans_object_base_flags(TransInfo *t)
|
||||
{
|
||||
ViewLayer *view_layer = t->view_layer;
|
||||
Base *base;
|
||||
@ -767,6 +769,149 @@ void createTransTexspace(TransInfo *t)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform (Auto-Keyframing)
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Auto-keyframing feature - for objects
|
||||
*
|
||||
* \param tmode: A transform mode.
|
||||
*
|
||||
* \note Context may not always be available,
|
||||
* so must check before using it as it's a luxury for a few cases.
|
||||
*/
|
||||
static void autokeyframe_object(
|
||||
bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
ID *id = &ob->id;
|
||||
FCurve *fcu;
|
||||
|
||||
// TODO: this should probably be done per channel instead...
|
||||
if (autokeyframe_cfra_can_key(scene, id)) {
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
|
||||
ListBase dsources = {NULL, NULL};
|
||||
float cfra = (float)CFRA; // xxx this will do for now
|
||||
eInsertKeyFlags flag = 0;
|
||||
|
||||
/* Get flags used for inserting keyframes. */
|
||||
flag = ANIM_get_keyframing_flags(scene, true);
|
||||
|
||||
/* add datasource override for the object */
|
||||
ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL);
|
||||
|
||||
if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
|
||||
/* Only insert into active keyingset
|
||||
* NOTE: we assume here that the active Keying Set
|
||||
* does not need to have its iterator overridden.
|
||||
*/
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
|
||||
AnimData *adt = ob->adt;
|
||||
|
||||
/* only key on available channels */
|
||||
if (adt && adt->action) {
|
||||
ListBase nla_cache = {NULL, NULL};
|
||||
for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
|
||||
insert_keyframe(bmain,
|
||||
reports,
|
||||
id,
|
||||
adt->action,
|
||||
(fcu->grp ? fcu->grp->name : NULL),
|
||||
fcu->rna_path,
|
||||
fcu->array_index,
|
||||
cfra,
|
||||
ts->keyframe_type,
|
||||
&nla_cache,
|
||||
flag);
|
||||
}
|
||||
|
||||
BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
|
||||
}
|
||||
}
|
||||
else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
|
||||
bool do_loc = false, do_rot = false, do_scale = false;
|
||||
|
||||
/* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
|
||||
if (tmode == TFM_TRANSLATION) {
|
||||
do_loc = true;
|
||||
}
|
||||
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
|
||||
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
|
||||
if (ob != OBACT(view_layer)) {
|
||||
do_loc = true;
|
||||
}
|
||||
}
|
||||
else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
|
||||
do_loc = true;
|
||||
}
|
||||
|
||||
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
|
||||
do_rot = true;
|
||||
}
|
||||
}
|
||||
else if (tmode == TFM_RESIZE) {
|
||||
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
|
||||
if (ob != OBACT(view_layer)) {
|
||||
do_loc = true;
|
||||
}
|
||||
}
|
||||
else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
|
||||
do_loc = true;
|
||||
}
|
||||
|
||||
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
|
||||
do_scale = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
|
||||
if (do_loc) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
if (do_rot) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
if (do_scale) {
|
||||
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
|
||||
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, ANIM_KS_LOC_ROT_SCALE_ID);
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
|
||||
}
|
||||
|
||||
/* free temp info */
|
||||
BLI_freelistN(&dsources);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return if we need to update motion paths, only if they already exist,
|
||||
* and we will insert a keyframe at the end of transform. */
|
||||
static bool motionpath_need_update_object(Scene *scene, Object *ob)
|
||||
{
|
||||
/* XXX: there's potential here for problems with unkeyed rotations/scale,
|
||||
* but for now (until proper data-locality for baking operations),
|
||||
* this should be a better fix for T24451 and T37755
|
||||
*/
|
||||
|
||||
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
|
||||
return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Recalc Data object
|
||||
*
|
||||
@ -829,3 +974,81 @@ void recalcData_objects(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Object
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__object(bContext *C, TransInfo *t)
|
||||
{
|
||||
BLI_assert(t->flag & (T_OBJECT | T_TEXTURE));
|
||||
|
||||
Object *ob;
|
||||
const bool canceled = (t->state == TRANS_CANCEL);
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
bool motionpath_update = false;
|
||||
|
||||
for (int i = 0; i < tc->data_len; i++) {
|
||||
TransData *td = tc->data + i;
|
||||
ListBase pidlist;
|
||||
PTCacheID *pid;
|
||||
ob = td->ob;
|
||||
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* flag object caches as outdated */
|
||||
BKE_ptcache_ids_from_object(&pidlist, ob, t->scene, MAX_DUPLI_RECUR);
|
||||
for (pid = pidlist.first; pid; pid = pid->next) {
|
||||
if (pid->type != PTCACHE_TYPE_PARTICLES) {
|
||||
/* particles don't need reset on geometry change */
|
||||
pid->cache->flag |= PTCACHE_OUTDATED;
|
||||
}
|
||||
}
|
||||
BLI_freelistN(&pidlist);
|
||||
|
||||
/* pointcache refresh */
|
||||
if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED)) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
/* Needed for proper updating of "quick cached" dynamics. */
|
||||
/* Creates troubles for moving animated objects without */
|
||||
/* autokey though, probably needed is an anim sys override? */
|
||||
/* Please remove if some other solution is found. -jahka */
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
|
||||
|
||||
/* Set autokey if necessary */
|
||||
if (!canceled) {
|
||||
autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
|
||||
}
|
||||
|
||||
motionpath_update |= motionpath_need_update_object(t->scene, ob);
|
||||
|
||||
/* restore rigid body transform */
|
||||
if (ob->rigidbody_object && canceled) {
|
||||
float ctime = BKE_scene_frame_get(t->scene);
|
||||
if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime)) {
|
||||
BKE_rigidbody_aftertrans_update(ob,
|
||||
td->ext->oloc,
|
||||
td->ext->orot,
|
||||
td->ext->oquat,
|
||||
td->ext->orotAxis,
|
||||
td->ext->orotAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (motionpath_update) {
|
||||
/* Update motion paths once for all transformed objects. */
|
||||
const eObjectPathCalcRange range = canceled ? OBJECT_PATH_CALC_RANGE_CURRENT_FRAME :
|
||||
OBJECT_PATH_CALC_RANGE_CHANGED;
|
||||
ED_objects_recalculate_paths(C, t->scene, range);
|
||||
}
|
||||
|
||||
clear_trans_object_base_flags(t);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_sequencer.h"
|
||||
|
||||
#include "ED_markers.h"
|
||||
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "transform.h"
|
||||
@ -808,6 +810,41 @@ void recalcData_sequencer(TransInfo *t)
|
||||
flushTransSeq(t);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Sequencer
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo *t)
|
||||
{
|
||||
if (t->state == TRANS_CANCEL) {
|
||||
return;
|
||||
}
|
||||
/* freeSeqData in transform_conversions.c does this
|
||||
* keep here so the else at the end wont run... */
|
||||
|
||||
SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first;
|
||||
|
||||
/* Marker transform, not especially nice but we may want to move markers
|
||||
* at the same time as strips in the Video Sequencer. */
|
||||
if (sseq->flag & SEQ_MARKER_TRANS) {
|
||||
/* cant use TFM_TIME_EXTEND
|
||||
* for some reason EXTEND is changed into TRANSLATE, so use frame_side instead */
|
||||
|
||||
if (t->mode == TFM_SEQ_SLIDE) {
|
||||
if (t->frame_side == 'B') {
|
||||
ED_markers_post_apply_transform(
|
||||
&t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values[0], t->frame_side);
|
||||
}
|
||||
}
|
||||
else if (ELEM(t->frame_side, 'L', 'R')) {
|
||||
ED_markers_post_apply_transform(
|
||||
&t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values[0], t->frame_side);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int transform_convert_sequencer_get_snap_bound(TransInfo *t)
|
||||
{
|
||||
TransSeq *ts = TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
|
||||
|
@ -25,15 +25,20 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_movieclip.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "ED_clip.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_convert.h"
|
||||
|
||||
@ -546,7 +551,14 @@ void createTransTrackingData(bContext *C, TransInfo *t)
|
||||
}
|
||||
}
|
||||
|
||||
void cancelTransTracking(TransInfo *t)
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name recalc Motion Tracking TransData
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static void cancelTransTracking(TransInfo *t)
|
||||
{
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
SpaceClip *sc = t->area->spacedata.first;
|
||||
@ -605,13 +617,6 @@ void cancelTransTracking(TransInfo *t)
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name recalc Motion Tracking TransData
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static void flushTransTracking(TransInfo *t)
|
||||
{
|
||||
TransData *td;
|
||||
@ -738,3 +743,47 @@ void recalcData_tracking(TransInfo *t)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Tracking
|
||||
* \{ */
|
||||
|
||||
void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
|
||||
{
|
||||
SpaceClip *sc = t->area->spacedata.first;
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
|
||||
const int framenr = ED_space_clip_get_clip_frame_number(sc);
|
||||
/* Update coordinates of modified plane tracks. */
|
||||
LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
|
||||
bool do_update = false;
|
||||
if (plane_track->flag & PLANE_TRACK_HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
do_update |= PLANE_TRACK_VIEW_SELECTED(plane_track) != 0;
|
||||
if (do_update == false) {
|
||||
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
|
||||
int i;
|
||||
for (i = 0; i < plane_track->point_tracksnr; i++) {
|
||||
MovieTrackingTrack *track = plane_track->point_tracks[i];
|
||||
if (TRACK_VIEW_SELECTED(sc, track)) {
|
||||
do_update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_update) {
|
||||
BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
|
||||
}
|
||||
}
|
||||
if (t->scene->nodetree != NULL) {
|
||||
/* Tracks can be used for stabilization nodes,
|
||||
* flush update for such nodes.
|
||||
*/
|
||||
nodeUpdateID(t->scene->nodetree, &clip->id);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
Loading…
Reference in New Issue
Block a user