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:
Diffstat (limited to 'source/blender/editors/transform/transform_conversions.c')
-rw-r--r--source/blender/editors/transform/transform_conversions.c1435
1 files changed, 1064 insertions, 371 deletions
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index b7098085ac2..c12418f1a0f 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <math.h>
+#include <limits.h>
#include "DNA_anim_types.h"
#include "DNA_brush_types.h"
@@ -54,11 +55,11 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLI_smallhash.h"
#include "BLI_listbase.h"
#include "BLI_linklist_stack.h"
#include "BLI_string.h"
#include "BLI_bitmap.h"
+#include "BLI_rect.h"
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
@@ -90,7 +91,6 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
-#include "BKE_lattice.h"
#include "BIK_api.h"
@@ -107,6 +107,7 @@
#include "ED_uvedit.h"
#include "ED_clip.h"
#include "ED_mask.h"
+#include "ED_gpencil.h"
#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
#include "WM_types.h"
@@ -218,6 +219,9 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
float _proj_vec[3];
const float *proj_vec = NULL;
+ /* support for face-islands */
+ const bool use_island = transdata_check_local_islands(t, t->around);
+
if (t->flag & T_PROP_PROJECTED) {
if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = t->ar->regiondata;
@@ -239,7 +243,12 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
for (i = 0, td = t->data; i < t->total; i++, td++) {
if (td->flag & TD_SELECTED) {
- sub_v3_v3v3(vec, tob->center, td->center);
+ if (use_island) {
+ sub_v3_v3v3(vec, tob->iloc, td->iloc);
+ }
+ else {
+ sub_v3_v3v3(vec, tob->center, td->center);
+ }
mul_m3_v3(tob->mtx, vec);
if (proj_vec) {
@@ -249,8 +258,12 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
}
dist_sq = len_squared_v3(vec);
- if ((tob->rdist == -1.0f) || (dist_sq < (tob->rdist * tob->rdist))) {
+ if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
tob->rdist = sqrtf(dist_sq);
+ if (use_island) {
+ copy_v3_v3(tob->center, td->center);
+ copy_m3_m3(tob->axismtx, td->axismtx);
+ }
}
}
else {
@@ -329,20 +342,20 @@ static void createTransEdge(TransInfo *t)
BMIter iter;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
int cd_edge_float_offset;
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
}
if (countsel == 0)
return;
- if (propmode) {
+ if (is_prop_edit) {
t->total = count;
}
else {
@@ -368,7 +381,7 @@ static void createTransEdge(TransInfo *t)
BLI_assert(cd_edge_float_offset != -1);
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || propmode)) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
float *fl_ptr;
/* need to set center for center calculations */
mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
@@ -616,10 +629,10 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
mul_m3_m3m3(td->axismtx, omat, pmat);
normalize_m3(td->axismtx);
- if (t->mode == TFM_BONESIZE) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
bArmature *arm = t->poseobj->data;
- if (arm->drawtype == ARM_ENVELOPE) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
td->val = &bone->dist;
td->ival = bone->dist;
@@ -706,7 +719,7 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
/* 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 (mode != TFM_BONESIZE) {
+ 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)
@@ -1056,11 +1069,13 @@ static void createTransPose(TransInfo *t, Object *ob)
void restoreBones(TransInfo *t)
{
+ bArmature *arm = t->obedit->data;
BoneInitData *bid = t->customData;
EditBone *ebo;
while (bid->bone) {
ebo = bid->bone;
+
ebo->dist = bid->dist;
ebo->rad_tail = bid->rad_tail;
ebo->roll = bid->roll;
@@ -1068,7 +1083,26 @@ void restoreBones(TransInfo *t)
ebo->zwidth = bid->zwidth;
copy_v3_v3(ebo->head, bid->head);
copy_v3_v3(ebo->tail, bid->tail);
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *ebo_child;
+
+ /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
+ for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
+ if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
+ copy_v3_v3(ebo_child->head, ebo->tail);
+ ebo_child->rad_head = ebo->rad_tail;
+ }
+ }
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ EditBone *parent = ebo->parent;
+ copy_v3_v3(parent->tail, ebo->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+
bid++;
}
}
@@ -1092,7 +1126,7 @@ static void createTransArmatureVerts(TransInfo *t)
oldtot = t->total;
if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (t->mode == TFM_BONESIZE) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
if (ebo->flag & BONE_SELECTED)
t->total++;
}
@@ -1170,9 +1204,9 @@ static void createTransArmatureVerts(TransInfo *t)
}
}
- else if (t->mode == TFM_BONESIZE) {
+ else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
if (ebo->flag & BONE_SELECTED) {
- if (arm->drawtype == ARM_ENVELOPE) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
td->val = &ebo->dist;
td->ival = ebo->dist;
@@ -1218,7 +1252,13 @@ static void createTransArmatureVerts(TransInfo *t)
else {
if (ebo->flag & BONE_TIPSEL) {
copy_v3_v3(td->iloc, ebo->tail);
- copy_v3_v3(td->center, (t->around == V3D_LOCAL) ? ebo->head : td->iloc);
+
+ /* don't allow single selected tips to have a modified center,
+ * causes problem with snapping T45974 */
+ copy_v3_v3(td->center,
+ ((t->around == V3D_LOCAL) &&
+ (ebo->flag & BONE_ROOTSEL)) ? ebo->head : td->iloc);
+
td->loc = ebo->tail;
td->flag = TD_SELECTED;
if (ebo->flag & BONE_EDITMODE_LOCKED)
@@ -1297,18 +1337,18 @@ static void createTransMBallVerts(TransInfo *t)
TransDataExtension *tx;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
/* count totals */
for (ml = mb->editelems->first; ml; ml = ml->next) {
if (ml->flag & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)");
@@ -1318,7 +1358,7 @@ static void createTransMBallVerts(TransInfo *t)
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (propmode || (ml->flag & SELECT)) {
+ if (is_prop_edit || (ml->flag & SELECT)) {
td->loc = &ml->x;
copy_v3_v3(td->iloc, td->loc);
copy_v3_v3(td->center, td->loc);
@@ -1431,7 +1471,7 @@ static void createTransCurveVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
ListBase *nurbs;
@@ -1446,13 +1486,13 @@ static void createTransCurveVerts(TransInfo *t)
if (bezt->hide == 0) {
if (hide_handles) {
if (bezt->f2 & SELECT) countsel += 3;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
else {
if (bezt->f1 & SELECT) countsel++;
if (bezt->f2 & SELECT) countsel++;
if (bezt->f3 & SELECT) countsel++;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
}
}
@@ -1460,7 +1500,7 @@ static void createTransCurveVerts(TransInfo *t)
else {
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode) count++;
+ if (is_prop_edit) count++;
if (bp->f1 & SELECT) countsel++;
}
}
@@ -1469,7 +1509,7 @@ static void createTransCurveVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)");
@@ -1504,7 +1544,7 @@ static void createTransCurveVerts(TransInfo *t)
}
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f1 & SELECT) && hide_handles == 0))
{
@@ -1538,7 +1578,7 @@ static void createTransCurveVerts(TransInfo *t)
}
/* This is the Curve Point, the other two are handles */
- if (propmode || (bezt->f2 & SELECT)) {
+ if (is_prop_edit || (bezt->f2 & SELECT)) {
copy_v3_v3(td->iloc, bezt->vec[1]);
td->loc = bezt->vec[1];
copy_v3_v3(td->center, td->loc);
@@ -1574,7 +1614,7 @@ static void createTransCurveVerts(TransInfo *t)
count++;
tail++;
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f3 & SELECT) && hide_handles == 0))
{
@@ -1611,17 +1651,17 @@ static void createTransCurveVerts(TransInfo *t)
(void)hdata; /* quiet warning */
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
/* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
* but for now just don't change handle types */
- if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0) {
+ if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
/* sets the handles based on their selection, do this after the data is copied to the TransData */
BKE_nurb_handles_test(nu, !hide_handles);
}
@@ -1631,7 +1671,7 @@ static void createTransCurveVerts(TransInfo *t)
head = tail = td;
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -1656,12 +1696,12 @@ static void createTransCurveVerts(TransInfo *t)
tail++;
}
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1677,14 +1717,14 @@ static void createTransLatticeVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
if (bp->hide == 0) {
if (bp->f1 & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
bp++;
}
@@ -1692,7 +1732,7 @@ static void createTransLatticeVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)");
@@ -1703,7 +1743,7 @@ static void createTransLatticeVerts(TransInfo *t)
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
if (bp->hide == 0) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
@@ -1711,7 +1751,9 @@ static void createTransLatticeVerts(TransInfo *t)
if (bp->f1 & SELECT) {
td->flag = TD_SELECTED;
}
- else td->flag = 0;
+ else {
+ td->flag = 0;
+ }
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
@@ -1742,7 +1784,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
float mat[4][4];
int i, k, transformparticle;
int count = 0, hasselected = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
@@ -1764,7 +1806,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
hasselected = 1;
transformparticle = 1;
}
- else if (propmode)
+ else if (is_prop_edit)
transformparticle = 1;
}
}
@@ -1814,7 +1856,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if (key->flag & PEK_SELECT)
td->flag |= TD_SELECTED;
- else if (!propmode)
+ else if (!is_prop_edit)
td->flag |= TD_SKIP;
unit_m3(td->mtx);
@@ -1843,7 +1885,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
tx++;
tail++;
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1859,7 +1901,8 @@ void flushTransParticles(TransInfo *t)
PTCacheEditKey *key;
TransData *td;
float mat[4][4], imat[4][4], co[3];
- int i, k, propmode = t->flag & T_PROP_EDIT;
+ int i, k;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (psys)
psmd = psys_get_modifier(ob, psys);
@@ -1880,7 +1923,7 @@ void flushTransParticles(TransInfo *t)
/* optimization for proportional edit */
- if (!propmode || !compare_v3v3(key->co, co, 0.0001f)) {
+ if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
copy_v3_v3(key->co, co);
point->flag |= PEP_EDIT_RECALC;
}
@@ -1938,17 +1981,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
int i;
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ float dist;
BM_elem_index_set(v, i); /* set_inline */
BM_elem_flag_disable(v, BM_ELEM_TAG);
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- dists[i] = FLT_MAX;
+ dist = FLT_MAX;
}
else {
BLI_LINKSTACK_PUSH(queue, v);
-
- dists[i] = 0.0f;
+ dist = 0.0f;
}
+
+ dists[i] = dists_prev[i] = dist;
}
bm->elem_index_dirty &= ~BM_VERT;
}
@@ -1957,55 +2002,77 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
BMVert *v;
LinkNode *lnk;
+ /* this is correct but slow to do each iteration,
+ * instead sync the dist's while clearing BM_ELEM_TAG (below) */
+#if 0
memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
+#endif
while ((v = BLI_LINKSTACK_POP(queue))) {
- /* quick checks */
- bool has_edges = (v->e != NULL);
- bool has_faces = false;
+ BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
/* connected edge-verts */
- if (has_edges) {
- BMIter iter;
- BMEdge *e;
+ if (v->e != NULL) {
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- has_faces |= (BM_edge_is_wire(e) == false);
+ /* would normally use BM_EDGES_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
- BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
+
+ /* edge distance */
+ BMVert *v_other = BM_edge_other_vert(e_iter, v);
if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
BLI_LINKSTACK_PUSH(queue_next, v_other);
}
}
- }
- }
- }
-
- /* imaginary edge diagonally across quad */
- if (has_faces) {
- BMIter iter;
- BMLoop *l;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len == 4)) {
- BMVert *v_other = l->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
+ /* face distance */
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ /**
+ * imaginary edge diagonally across quad,
+ * \note, this takes advantage of the rules of winding that we
+ * know 2 or more of a verts edges wont reference the same face twice.
+ * Also, if the edge is hidden, the face will be hidden too.
+ */
+ l_iter_radial = l_first_radial = e_iter->l;
+
+ do {
+ if ((l_iter_radial->v == v) &&
+ (l_iter_radial->f->len == 4) &&
+ (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0))
+ {
+ BMVert *v_other = l_iter_radial->next->next->v;
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
+ }
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
}
}
- }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
}
}
+
/* clear for the next loop */
for (lnk = queue_next; lnk; lnk = lnk->next) {
- BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG);
+ BMVert *v = lnk->link;
+ const int i = BM_elem_index_get(v);
+
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ /* keep in sync, avoid having to do full memcpy each iteration */
+ dists_prev[i] = dists[i];
}
BLI_LINKSTACK_SWAP(queue, queue_next);
@@ -2063,7 +2130,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
* its possible we have a selected vertex thats not in a face, for now best not crash in that case. */
- fill_vn_i(vert_map, bm->totvert, -1);
+ copy_vn_i(vert_map, bm->totvert, -1);
BM_mesh_elem_table_ensure(bm, htype);
ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
@@ -2144,6 +2211,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
BMEditMesh *em, BMVert *eve, float *bweight,
struct TransIslandData *v_island)
{
+ float *no, _no[3];
BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
td->flag = 0;
@@ -2153,19 +2221,30 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
td->loc = eve->co;
copy_v3_v3(td->iloc, td->loc);
+ if ((t->mode == TFM_SHRINKFATTEN) &&
+ (em->selectmode & SCE_SELECT_FACE) &&
+ BM_elem_flag_test(eve, BM_ELEM_SELECT) &&
+ (BM_vert_normal_update_ex(eve, BM_ELEM_SELECT, _no)))
+ {
+ no = _no;
+ }
+ else {
+ no = eve->no;
+ }
+
if (v_island) {
copy_v3_v3(td->center, v_island->co);
copy_m3_m3(td->axismtx, v_island->axismtx);
}
else if (t->around == V3D_LOCAL) {
copy_v3_v3(td->center, td->loc);
- createSpaceNormal(td->axismtx, eve->no);
+ createSpaceNormal(td->axismtx, no);
}
else {
copy_v3_v3(td->center, td->loc);
/* Setting normals */
- copy_v3_v3(td->axismtx[2], eve->no);
+ copy_v3_v3(td->axismtx[2], no);
td->axismtx[0][0] =
td->axismtx[0][1] =
td->axismtx[0][2] =
@@ -2194,7 +2273,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
}
else if (t->mode == TFM_SHRINKFATTEN) {
td->ext = tx;
- tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, BM_ELEM_SELECT);
+ tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
}
}
@@ -2211,7 +2290,7 @@ static void createTransEditVerts(TransInfo *t)
float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
float *dists = NULL;
int a;
- int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int mirror = 0;
int cd_vert_bweight_offset = -1;
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
@@ -2251,7 +2330,7 @@ static void createTransEditVerts(TransInfo *t)
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
- if (propmode) {
+ if (prop_mode) {
unsigned int count = 0;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
@@ -2262,7 +2341,7 @@ static void createTransEditVerts(TransInfo *t)
t->total = count;
/* allocating scratch arrays */
- if (propmode & T_PROP_CONNECTED)
+ if (prop_mode & T_PROP_CONNECTED)
dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
}
else {
@@ -2284,7 +2363,7 @@ static void createTransEditVerts(TransInfo *t)
* matrix inversion still works and we can still moving along the other */
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode & T_PROP_CONNECTED) {
editmesh_set_connectivity_distance(em->bm, mtx, dists);
}
@@ -2298,7 +2377,7 @@ static void createTransEditVerts(TransInfo *t)
if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) {
/* check if we can use deform matrices for modifier from the
* start up to stack, they are more accurate than quats */
- totleft = editbmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos);
+ totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->scene, t->obedit, em, &defmats, &defcos);
}
/* if we still have more modifiers, also do crazyspace
@@ -2313,7 +2392,7 @@ static void createTransEditVerts(TransInfo *t)
{
mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit);
quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
- BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !propmode);
+ BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
if (mappedcos)
MEM_freeN(mappedcos);
}
@@ -2338,7 +2417,7 @@ static void createTransEditVerts(TransInfo *t)
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
struct TransIslandData *v_island = (island_info && island_vert_map[a] != -1) ?
&island_info[island_vert_map[a]] : NULL;
float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
@@ -2351,8 +2430,8 @@ static void createTransEditVerts(TransInfo *t)
if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
tob->flag |= TD_SELECTED;
- if (propmode) {
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
tob->dist = dists[a];
}
else {
@@ -2604,24 +2683,23 @@ void flushTransSeq(TransInfo *t)
/* ********************* UV ****************** */
-static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, float *uv, int selected)
+static void UVsToTransData(
+ const float aspect[2], TransData *td, TransData2D *td2d,
+ float *uv, const float *center, bool selected)
{
- float aspx, aspy;
-
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
-
/* uv coords are scaled by aspects. this is needed for rotations and
* proportional editing to be consistent with the stretched uv coords
* that are displayed. this also means that for display and numinput,
- * and when the the uv coords are flushed, these are converted each time */
- td2d->loc[0] = uv[0] * aspx;
- td2d->loc[1] = uv[1] * aspy;
+ * and when the uv coords are flushed, these are converted each time */
+ td2d->loc[0] = uv[0] * aspect[0];
+ td2d->loc[1] = uv[1] * aspect[1];
td2d->loc[2] = 0.0f;
td2d->loc2d = uv;
td->flag = 0;
td->loc = td2d->loc;
- copy_v3_v3(td->center, td->loc);
+ copy_v2_v2(td->center, center ? center : td->loc);
+ td->center[2] = 0.0f;
copy_v3_v3(td->iloc, td->loc);
memset(td->axismtx, 0, sizeof(td->axismtx));
@@ -2648,36 +2726,43 @@ static void createTransUVs(bContext *C, TransInfo *t)
ToolSettings *ts = CTX_data_tool_settings(C);
TransData *td = NULL;
TransData2D *td2d = NULL;
- MTexPoly *tf;
- MLoopUV *luv;
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMFace *efa;
- BMLoop *l;
BMIter iter, liter;
UvElementMap *elementmap = NULL;
BLI_bitmap *island_enabled = NULL;
+ struct { float co[2]; int co_num; } *island_center = NULL;
int count = 0, countsel = 0, count_rejected = 0;
- const bool propmode = (t->flag & T_PROP_EDIT) != 0;
- const bool propconnected = (t->flag & T_PROP_CONNECTED) != 0;
-
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_island_center = (t->around == V3D_LOCAL);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- if (!ED_space_image_show_uvedit(sima, t->obedit)) return;
+ if (!ED_space_image_show_uvedit(sima, t->obedit))
+ return;
/* count */
- if (propconnected) {
+ if (is_prop_connected || is_island_center) {
/* create element map with island information */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- elementmap = BM_uv_element_map_create(em->bm, false, true);
+ const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
+ elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
+ if (elementmap == NULL) {
+ return;
}
- else {
- elementmap = BM_uv_element_map_create(em->bm, true, true);
+
+ if (is_prop_connected) {
+ island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
+ }
+
+ if (is_island_center) {
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
}
- island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ BMLoop *l;
if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
@@ -2689,14 +2774,25 @@ static void createTransUVs(bContext *C, TransInfo *t)
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
countsel++;
- if (propconnected) {
+ if (is_prop_connected || island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- BLI_BITMAP_ENABLE(island_enabled, element->island);
- }
+ if (is_prop_connected) {
+ BLI_BITMAP_ENABLE(island_enabled, element->island);
+ }
+
+ if (is_island_center) {
+ if (element->flag == false) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(island_center[element->island].co, luv->uv);
+ island_center[element->island].co_num++;
+ element->flag = true;
+ }
+ }
+ }
}
- if (propmode) {
+ if (is_prop_edit) {
count++;
}
}
@@ -2704,13 +2800,19 @@ static void createTransUVs(bContext *C, TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) {
- if (propconnected) {
- MEM_freeN(island_enabled);
+ goto finally;
+ }
+
+ if (is_island_center) {
+ int i;
+
+ for (i = 0; i < elementmap->totalIslands; i++) {
+ mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
+ mul_v2_v2(island_center[i].co, t->aspect);
}
- return;
}
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -2723,56 +2825,88 @@ static void createTransUVs(bContext *C, TransInfo *t)
td2d = t->data2d;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
+
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (!propmode && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
+ const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ MLoopUV *luv;
+ const float *center = NULL;
+
+ if (!is_prop_edit && !selected)
continue;
- if (propconnected) {
+ if (is_prop_connected || is_island_center) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
+
+ if (is_prop_connected) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
+ count_rejected++;
+ continue;
+ }
+ }
+
+ if (is_island_center) {
+ center = island_center[element->island].co;
}
}
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVsToTransData(sima, td++, td2d++, luv->uv, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
+ UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
}
}
- if (propconnected) {
+ if (is_prop_connected) {
t->total -= count_rejected;
- BM_uv_element_map_free(elementmap);
- MEM_freeN(island_enabled);
}
if (sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
+
+
+finally:
+ if (is_prop_connected || is_island_center) {
+ BM_uv_element_map_free(elementmap);
+
+ if (is_prop_connected) {
+ MEM_freeN(island_enabled);
+ }
+
+ if (island_center) {
+ MEM_freeN(island_center);
+ }
+ }
}
void flushTransUVs(TransInfo *t)
{
SpaceImage *sima = t->sa->spacedata.first;
TransData2D *td;
- int a, width, height;
- float aspx, aspy, invx, invy;
+ int a;
+ float aspect_inv[2], size[2];
+ const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL));
+
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
- ED_space_image_get_size(sima, &width, &height);
- invx = 1.0f / aspx;
- invy = 1.0f / aspy;
+ if (use_pixel_snap) {
+ int size_i[2];
+ ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
+ size[0] = size_i[0];
+ size[1] = size_i[1];
+ }
/* flush to 2d vector from internally used 3d vector */
for (a = 0, td = t->data2d; a < t->total; a++, td++) {
- td->loc2d[0] = td->loc[0] * invx;
- td->loc2d[1] = td->loc[1] * invy;
+ td->loc2d[0] = td->loc[0] * aspect_inv[0];
+ td->loc2d[1] = td->loc[1] * aspect_inv[1];
- if ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
- td->loc2d[0] = (float)floor(width * td->loc2d[0] + 0.5f) / width;
- td->loc2d[1] = (float)floor(height * td->loc2d[1] + 0.5f) / height;
+ if (use_pixel_snap) {
+ td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0];
+ td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
}
}
}
@@ -2780,44 +2914,45 @@ void flushTransUVs(TransInfo *t)
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
{
TransData *td;
- int a, clipx = 1, clipy = 1;
- float aspx, aspy, min[2], max[2];
+ int a;
+ bool clipx = true, clipy = true;
+ float min[2], max[2];
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
min[0] = min[1] = 0.0f;
- max[0] = aspx; max[1] = aspy;
+ max[0] = t->aspect[0];
+ max[1] = t->aspect[1];
for (a = 0, td = t->data; a < t->total; a++, td++) {
minmax_v2v2_v2(min, max, td->loc);
}
if (resize) {
- if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx * 0.5f)
+ if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < t->aspect[0] * 0.5f)
vec[0] *= t->center[0] / (t->center[0] - min[0]);
- else if (max[0] > aspx && t->center[0] < aspx)
- vec[0] *= (t->center[0] - aspx) / (t->center[0] - max[0]);
+ else if (max[0] > t->aspect[0] && t->center[0] < t->aspect[0])
+ vec[0] *= (t->center[0] - t->aspect[0]) / (t->center[0] - max[0]);
else
clipx = 0;
- if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy * 0.5f)
+ if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < t->aspect[1] * 0.5f)
vec[1] *= t->center[1] / (t->center[1] - min[1]);
- else if (max[1] > aspy && t->center[1] < aspy)
- vec[1] *= (t->center[1] - aspy) / (t->center[1] - max[1]);
+ else if (max[1] > t->aspect[1] && t->center[1] < t->aspect[1])
+ vec[1] *= (t->center[1] - t->aspect[1]) / (t->center[1] - max[1]);
else
clipy = 0;
}
else {
if (min[0] < 0.0f)
vec[0] -= min[0];
- else if (max[0] > aspx)
- vec[0] -= max[0] - aspx;
+ else if (max[0] > t->aspect[0])
+ vec[0] -= max[0] - t->aspect[0];
else
clipx = 0;
if (min[1] < 0.0f)
vec[1] -= min[1];
- else if (max[1] > aspy)
- vec[1] -= max[1] - aspy;
+ else if (max[1] > t->aspect[1])
+ vec[1] -= max[1] - t->aspect[1];
else
clipy = 0;
}
@@ -2829,9 +2964,6 @@ void clipUVData(TransInfo *t)
{
TransData *td = NULL;
int a;
- float aspx, aspy;
-
- ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
for (a = 0, td = t->data; a < t->total; a++, td++) {
if (td->flag & TD_NOACTION)
@@ -2840,8 +2972,8 @@ void clipUVData(TransInfo *t)
if ((td->flag & TD_SKIP) || (!td->loc))
continue;
- td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), aspx);
- td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), aspy);
+ td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
+ td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
}
}
@@ -3115,7 +3247,7 @@ static void posttrans_gpd_clean(bGPdata *gpd)
bGPDframe *gpf, *gpfn;
bool is_double = false;
- BLI_sortlist_r(&gpl->frames, &is_double, gpf_cmp_frame);
+ BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
if (is_double) {
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
@@ -3142,7 +3274,7 @@ static void posttrans_mask_clean(Mask *mask)
MaskLayerShape *masklay_shape, *masklay_shape_next;
bool is_double = false;
- BLI_sortlist_r(&masklay->splines_shapes, &is_double, masklay_shape_cmp_frame);
+ 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) {
@@ -3164,7 +3296,7 @@ static void posttrans_mask_clean(Mask *mask)
/* Called during special_aftertrans_update to make sure selected keyframes replace
* any other keyframes which may reside on that frame (that is not selected).
*/
-static void posttrans_fcurve_clean(FCurve *fcu, const short use_handle)
+static void posttrans_fcurve_clean(FCurve *fcu, const bool use_handle)
{
float *selcache; /* cache for frame numbers of selected frames (fcu->totvert*sizeof(float)) */
int len, index, i; /* number of frames in cache, item index */
@@ -3186,7 +3318,7 @@ static void posttrans_fcurve_clean(FCurve *fcu, const short use_handle)
for (i = 0; i < fcu->totvert; i++) {
BezTriple *bezt = &fcu->bezt[i];
- if (BEZSELECTED(bezt)) {
+ if (BEZT_ISSEL_ANY(bezt)) {
selcache[index] = bezt->vec[1][0];
index++;
len++;
@@ -3200,7 +3332,7 @@ static void posttrans_fcurve_clean(FCurve *fcu, const short use_handle)
for (i = fcu->totvert - 1; i >= 0; i--) {
BezTriple *bezt = &fcu->bezt[i];
- if (BEZSELECTED(bezt) == 0) {
+ if (BEZT_ISSEL_ANY(bezt) == 0) {
/* check beztriple should be removed according to cache */
for (index = 0; index < len; index++) {
if (IS_EQF(bezt->vec[1][0], selcache[index])) {
@@ -3258,76 +3390,90 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
/* ----------------------------- */
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_fcurve_keys(FCurve *fcu, char side, float cfra)
+static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
{
BezTriple *bezt;
- int i, count = 0;
+ int i, count = 0, count_all = 0;
if (ELEM(NULL, fcu, fcu->bezt))
return count;
/* only include points that occur on the right side of cfra */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (bezt->f2 & SELECT) {
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
/* no need to adjust the handle selection since they are assumed
* selected (like graph editor with SIPO_NOHANDLES) */
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- count += 1;
- }
+ if (bezt->f2 & SELECT)
+ count++;
+
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
{
bGPDframe *gpf;
- int count = 0;
+ int count = 0, count_all = 0;
if (gpl == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra))
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ if (gpf->flag & GP_FRAME_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra)
+static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
{
MaskLayerShape *masklayer_shape;
- int count = 0;
+ int count = 0, count_all = 0;
if (masklay == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape; masklayer_shape = masklayer_shape->next) {
- if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
- if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra))
+ if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
+ if (masklayer_shape->flag & MASK_SHAPE_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* This function assigns the information to transdata */
-static void TimeToTransData(TransData *td, float *time, AnimData *adt)
+static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
{
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = time;
td->ival = *(time);
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
/* store the AnimData where this keyframe exists as a keyframe of the
* active action as td->extra.
*/
@@ -3341,7 +3487,7 @@ static void TimeToTransData(TransData *td, float *time, AnimData *adt)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra)
+static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra, bool is_prop_edit, float ypos)
{
BezTriple *bezt;
TransData2D *td2d = *td2dv;
@@ -3352,11 +3498,14 @@ static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FC
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
/* only add selected keyframes (for now, proportional edit is not enabled) */
- if (bezt->f2 & SELECT) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */
+ if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(), so can't use BEZT_ISSEL_ANY() macro */
/* only add if on the right 'side' of the current frame */
if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- TimeToTransData(td, bezt->vec[1], adt);
+ TimeToTransData(td, bezt->vec[1], adt, ypos);
+ if (bezt->f2 & SELECT)
+ td->flag |= TD_SELECTED;
+
/*set flags to move handles as necessary*/
td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
td2d->h1 = bezt->vec[0];
@@ -3407,19 +3556,22 @@ void flushTransIntFrameActionData(TransInfo *t)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra)
+static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra, bool is_prop_edit, float ypos)
{
bGPDframe *gpf;
int count = 0;
/* check for select frames on right side of current frame */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
+ if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)gpf->framenum;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)gpf->framenum;
tfd->sdata = &gpf->framenum;
@@ -3435,19 +3587,22 @@ static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl,
}
/* refer to comment above #GPLayerToTransData, this is the same but for masks */
-static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra)
+static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra, bool is_prop_edit, float ypos)
{
MaskLayerShape *masklay_shape;
int count = 0;
/* check for select frames on right side of current frame */
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)masklay_shape->frame;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)masklay_shape->frame;
tfd->sdata = &masklay_shape->frame;
@@ -3469,15 +3624,25 @@ static void createTransActionData(bContext *C, TransInfo *t)
TransData *td = NULL;
TransData2D *td2d = NULL;
tGPFtransdata *tfd = NULL;
-
+
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
-
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
int count = 0;
float cfra;
-
+ float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
+
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
@@ -3505,7 +3670,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 1: fully select ipo-keys and count how many BezTriples are selected */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
-
+ int adt_count = 0;
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
*/
@@ -3514,14 +3679,19 @@ static void createTransActionData(bContext *C, TransInfo *t)
else
cfra = (float)CFRA;
- if (ale->type == ANIMTYPE_FCURVE)
- count += count_fcurve_keys(ale->key_data, t->frame_side, cfra);
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
+ adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_GPLAYER)
- count += count_gplayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_MASKLAYER)
- count += count_masklayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else
BLI_assert(0);
+
+ if (adt_count > 0) {
+ count += adt_count;
+ ale->tag = true;
+ }
}
/* stop if trying to build list if nothing selected */
@@ -3558,11 +3728,22 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ if (is_prop_edit && !ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
if (ale->type == ANIMTYPE_GPLAYER) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
int i;
- i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra);
+ i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3570,7 +3751,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
MaskLayer *masklay = (MaskLayer *)ale->data;
int i;
- i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra);
+ i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3578,15 +3759,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
-
- td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra);
+ td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
}
}
@@ -3615,6 +3788,109 @@ static void createTransActionData(bContext *C, TransInfo *t)
*((float *)(t->customData) + 1) = max;
}
+ /* calculate distances for proportional editing */
+ if (is_prop_edit) {
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ /* F-Curve may not have any keyframes */
+ if (!ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ bGPDframe *gpf_iter;
+ int min = INT_MAX;
+ for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf->next) {
+ if (gpf_iter->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
+ int val = abs(gpf->framenum - gpf_iter->framenum);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ MaskLayerShape *masklay_shape;
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ MaskLayerShape *masklay_iter;
+ int min = INT_MAX;
+ for (masklay_iter = masklay->splines_shapes.first; masklay_iter; masklay_iter = masklay_iter->next) {
+ if (masklay_iter->flag & MASK_SHAPE_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
+ int val = abs(masklay_shape->frame - masklay_iter->frame);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ else {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ BezTriple *bezt;
+ int i;
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ if (bezt->f2 & SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ BezTriple *bezt_iter;
+ int j;
+ float min = FLT_MAX;
+ for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
+ if (bezt_iter->f2 & SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
+ float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
+ if (val < min)
+ min = val;
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ }
+ }
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -3623,6 +3899,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
typedef struct TransDataGraph {
float unit_scale;
+ float offset;
} TransDataGraph;
/* Helper function for createTransGraphEditData, which is responsible for associating
@@ -3631,7 +3908,7 @@ typedef struct TransDataGraph {
static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *tdg,
AnimData *adt, BezTriple *bezt,
int bi, bool selected, bool ishandle, bool intvals,
- float mtx[3][3], float smtx[3][3], float unit_scale)
+ float mtx[3][3], float smtx[3][3], float unit_scale, float offset)
{
float *loc = bezt->vec[bi];
const float *cent = bezt->vec[1];
@@ -3645,26 +3922,26 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
if (adt) {
td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
- td->center[1] = cent[1] * unit_scale;
+ td->center[1] = (cent[1] + offset) * unit_scale;
td->center[2] = 0.0f;
copy_v3_v3(td->iloc, td->loc);
}
else {
td2d->loc[0] = loc[0];
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
copy_v3_v3(td->center, cent);
- td->center[1] *= unit_scale;
+ td->center[1] = (td->center[1] + offset) * unit_scale;
copy_v3_v3(td->iloc, td->loc);
}
@@ -3704,6 +3981,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
copy_m3_m3(td->smtx, smtx);
tdg->unit_scale = unit_scale;
+ tdg->offset = offset;
}
static bool graph_edit_is_translation_mode(TransInfo *t)
@@ -3716,6 +3994,29 @@ static bool graph_edit_use_local_center(TransInfo *t)
return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t);
}
+
+static void graph_key_shortest_dist(TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
+{
+ int j = 0;
+ TransData *td_iter = td_start;
+
+ td->dist = FLT_MAX;
+ for (; j < fcu->totvert; j++) {
+ BezTriple *bezt = fcu->bezt + j;
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2 || sel3) {
+ td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
+ }
+
+ td_iter += 3;
+ }
+ }
+}
+
static void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
@@ -3734,11 +4035,11 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
BezTriple *bezt;
int count = 0, i;
- float cfra;
float mtx[3][3], smtx[3][3];
const bool is_translation_mode = graph_edit_is_translation_mode(t);
const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
const bool use_local_center = graph_edit_use_local_center(t);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
/* determine what type of data we are operating on */
@@ -3769,7 +4070,14 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
-
+ float cfra;
+ int curvecount = 0;
+ bool selected = false;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL)
+ continue;
+
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
*/
@@ -3777,48 +4085,44 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL)
- continue;
-
+
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = bezt->f2 & SELECT;
- const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2;
- const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2;
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (is_prop_edit) {
+ curvecount += 3;
+ if (sel2 || sel1 || sel3)
+ selected = true;
+ }
+ else {
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ count++;
+ }
- if (is_translation_mode) {
- /* for 'normal' pivots - just include anything that is selected.
- * this works a bit differently in translation modes */
- if (sel2) {
- count++;
- }
- else {
- if (sel1) count++;
- if (sel3) count++;
+ if (sel3) {
+ count++;
+ }
}
- }
- else if (use_local_center) {
- /* for local-pivot we only need to count the number of selected handles only,
- * so that centerpoints don't get moved wrong
- */
- if (bezt->ipo == BEZT_IPO_BEZ) {
- if (sel1) count++;
- if (sel3) count++;
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ count++;
}
- /* else if (sel2) count++; // TODO: could this cause problems? */
- /* - yes this causes problems, because no td is created for the center point */
- }
- else {
- /* for 'normal' pivots - just include anything that is selected */
- if (sel1) count++;
- if (sel2) count++;
- if (sel3) count++;
}
}
}
+
+ if (is_prop_edit) {
+ if (selected) {
+ count += curvecount;
+ ale->tag = true;
+ }
+ }
}
/* stop if trying to build list if nothing selected */
@@ -3864,8 +4168,13 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- bool intvals = (fcu->flag & FCURVE_INT_VALUES);
- float unit_scale;
+ bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
+ float unit_scale, offset;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0))
+ continue;
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
@@ -3874,83 +4183,148 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
-
- /* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL)
- continue;
-
- unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag);
+
+ unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const bool sel2 = bezt->f2 & SELECT;
- const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2;
- const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2;
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
TransDataCurveHandleFlags *hdata = NULL;
/* short h1=1, h2=1; */ /* UNUSED */
- /* only include handles if selected, irrespective of the interpolation modes.
- * also, only treat handles specially if the center point isn't selected.
- */
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale);
+ if (is_prop_edit) {
+ bool is_sel = (sel2 || sel1 || sel3);
+ /* we always select all handles for proportional editing if central handle is selected */
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, is_sel, false, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* only include handles if selected, irrespective of the interpolation modes.
+ * also, only treat handles specially if the center point isn't selected.
+ */
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h1 = 0; */ /* UNUSED */
+ }
+
+ if (sel3) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h2 = 0; */ /* UNUSED */
+ }
}
- else {
- /* h1 = 0; */ /* UNUSED */
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ /* move handles relative to center */
+ if (is_translation_mode) {
+ if (sel1) td->flag |= TD_MOVEHANDLE1;
+ if (sel3) td->flag |= TD_MOVEHANDLE2;
+ }
+
+ /* if handles were not selected, store their selection status */
+ if (!(sel1) || !(sel3)) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale, offset);
+
}
-
- if (sel3) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale);
+ /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
+ * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
+ * then check if we're using auto-handles.
+ * - If so, change them auto-handles to aligned handles so that handles get affected too
+ */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
+ {
+ if (hdata && (sel1) && (sel3)) {
+ bezt->h1 = HD_ALIGN;
+ bezt->h2 = HD_ALIGN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Sets handles based on the selection */
+ testhandles_fcurve(fcu, use_handle);
+ }
+
+ if (is_prop_edit) {
+ /* loop 2: build transdata arrays */
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ TransData *td_start = td;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (ale->tag == 0))
+ continue;
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2) {
+ td->dist = td->rdist = 0.0f;
}
else {
- /* h2 = 0; */ /* UNUSED */
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- /* move handles relative to center */
- if (is_translation_mode) {
- if (sel1) td->flag |= TD_MOVEHANDLE1;
- if (sel3) td->flag |= TD_MOVEHANDLE2;
+ td++;
+
+ if (sel2) {
+ td->dist = td->rdist = 0.0f;
}
-
- /* if handles were not selected, store their selection status */
- if (!(sel1) || !(sel3)) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
-
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale);
-
- }
- /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
- * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
- * then check if we're using auto-handles.
- * - If so, change them auto-handles to aligned handles so that handles get affected too
- */
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
- {
- if (hdata && (sel1) && (sel3)) {
- bezt->h1 = HD_ALIGN;
- bezt->h2 = HD_ALIGN;
+ td++;
+
+ if (sel3 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
+ td++;
}
}
}
-
- /* Sets handles based on the selection */
- testhandles_fcurve(fcu, use_handle);
}
-
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -4130,7 +4504,7 @@ void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
bAnimListElem *ale;
- const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
/* sort and reassign verts */
for (ale = anim_data->first; ale; ale = ale->next) {
@@ -4234,7 +4608,7 @@ void flushTransGraphData(TransInfo *t)
if (td->flag & TD_INTVALUES)
td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f);
else
- td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale;
+ td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
@@ -4493,10 +4867,47 @@ static int SeqToTransData_Recursive(TransInfo *t, ListBase *seqbase, TransData *
}
}
}
-
return tot;
}
+
+static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
+{
+ Sequence *seq;
+ int recursive, count, flag;
+ int max = INT32_MIN, min = INT32_MAX;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+
+ /* just to get the flag since there are corner cases where this isn't totally obvious */
+ SeqTransInfo(t, seq, &recursive, &count, &flag);
+
+ /* use 'flag' which is derived from seq->flag but modified for special cases */
+ if (flag & SELECT) {
+ if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
+ if (flag & SEQ_LEFTSEL) {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->startdisp, max);
+ }
+ if (flag & SEQ_RIGHTSEL) {
+ min = min_ii(seq->enddisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ else {
+ min = min_ii(seq->startdisp, min);
+ max = max_ii(seq->enddisp, max);
+ }
+ }
+ }
+
+ if (ts) {
+ ts->max = max;
+ ts->min = min;
+ }
+}
+
+
static void freeSeqData(TransInfo *t)
{
Editing *ed = BKE_sequencer_editing_get(t->scene, false);
@@ -4659,6 +5070,8 @@ static void freeSeqData(TransInfo *t)
}
if ((t->customData != NULL) && (t->flag & T_FREE_CUSTOMDATA)) {
+ TransSeq *ts = t->customData;
+ MEM_freeN(ts->tdseq);
MEM_freeN(t->customData);
t->customData = NULL;
}
@@ -4678,6 +5091,8 @@ static void createTransSeqData(bContext *C, TransInfo *t)
TransData *td = NULL;
TransData2D *td2d = NULL;
TransDataSeq *tdsq = NULL;
+ TransSeq *ts = NULL;
+ int xmouse;
int count = 0;
@@ -4688,12 +5103,11 @@ static void createTransSeqData(bContext *C, TransInfo *t)
t->customFree = freeSeqData;
+ xmouse = (int)UI_view2d_region_to_view_x(v2d, t->imval[0]);
+
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
/* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
}
else {
@@ -4733,15 +5147,19 @@ static void createTransSeqData(bContext *C, TransInfo *t)
return;
}
+ t->customData = ts = MEM_mallocN(sizeof(TransSeq), "transseq");
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransSeq TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransSeq TransData2D");
- tdsq = t->customData = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq");
+ ts->tdseq = tdsq = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq");
t->flag |= T_FREE_CUSTOMDATA;
-
-
/* loop 2: build transdata array */
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
+ SeqTransDataBounds(t, ed->seqbasep, ts);
+
+ /* set the snap mode based on how close the mouse is at the end/start points */
+ if (abs(xmouse - ts->max) > abs(xmouse - ts->min))
+ ts->snap_left = true;
#undef XXX_DURIAN_ANIM_TX_HACK
}
@@ -4769,7 +5187,6 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
/* (affirmative) returns for specific constraints here... */
/* constraints that require this regardless */
if (ELEM(con->type,
- CONSTRAINT_TYPE_CHILDOF,
CONSTRAINT_TYPE_FOLLOWPATH,
CONSTRAINT_TYPE_CLAMPTO,
CONSTRAINT_TYPE_OBJECTSOLVER,
@@ -4779,7 +5196,14 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
}
/* constraints that require this only under special conditions */
- if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+ if (con->type == CONSTRAINT_TYPE_CHILDOF) {
+ /* ChildOf constraint only works when using all location components, see T42256. */
+ bChildOfConstraint *data = (bChildOfConstraint *)con->data;
+
+ if ((data->flag & CHILDOF_LOCX) && (data->flag & CHILDOF_LOCY) && (data->flag & CHILDOF_LOCZ))
+ return true;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
/* CopyRot constraint only does this when rotating, and offset is on */
bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
@@ -4997,7 +5421,9 @@ static void set_trans_object_base_flags(TransInfo *t)
}
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5074,7 +5500,9 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
DAG_scene_relations_update(G.main, t->scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5271,7 +5699,7 @@ 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 && strcmp(pchanName, pchan->name) == 0)
+ 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);
@@ -5514,6 +5942,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
* during cleanup - psy-fi */
freeEdgeSlideTempFaces(sld);
}
+ else if (t->mode == TFM_VERT_SLIDE) {
+ /* as above */
+ VertSlideData *sld = t->customData;
+ projectVertSlideData(t, true);
+ freeVertSlideTempFaces(sld);
+ }
if (t->obedit->type == OB_MESH) {
special_aftertrans_update__mesh(C, t);
@@ -5526,12 +5960,21 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
sld->perc = 0.0;
projectEdgeSlideData(t, false);
}
+ else if (t->mode == TFM_VERT_SLIDE) {
+ VertSlideData *sld = t->customData;
+
+ sld->perc = 0.0;
+ projectVertSlideData(t, false);
+ }
}
}
}
- if (t->spacetype == SPACE_SEQ) {
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* pass */
+ }
+ else if (t->spacetype == SPACE_SEQ) {
/* freeSeqData in transform_conversions.c does this
* keep here so the else at the end wont run... */
@@ -5714,7 +6157,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
bAnimContext ac;
- const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
+ const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
/* initialize relevant anim-context 'context' data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -5941,7 +6384,7 @@ static void createTransObject(bContext *C, TransInfo *t)
TransData *td = NULL;
TransDataExtension *tx;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
set_trans_object_base_flags(t);
@@ -5954,7 +6397,7 @@ static void createTransObject(bContext *C, TransInfo *t)
return;
}
- if (propmode) {
+ if (is_prop_edit) {
t->total += count_proportional_objects(t);
}
@@ -5987,7 +6430,7 @@ static void createTransObject(bContext *C, TransInfo *t)
}
CTX_DATA_END;
- if (propmode) {
+ if (is_prop_edit) {
View3D *v3d = t->view;
Base *base;
@@ -6141,22 +6584,22 @@ typedef struct TransDataTracking {
static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
MovieTrackingTrack *track, MovieTrackingMarker *marker,
- int area, float loc[2], float rel[2], const float off[2], float aspx, float aspy)
+ int area, float loc[2], float rel[2], const float off[2], const float aspect[2])
{
int anchor = area == TRACK_AREA_POINT && off;
tdt->mode = transDataTracking_ModeTracks;
if (anchor) {
- td2d->loc[0] = rel[0] * aspx; /* hold original location */
- td2d->loc[1] = rel[1] * aspy;
+ td2d->loc[0] = rel[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = rel[1] * aspect[1];
tdt->loc = loc;
td2d->loc2d = loc; /* current location */
}
else {
- td2d->loc[0] = loc[0] * aspx; /* hold original location */
- td2d->loc[1] = loc[1] * aspy;
+ td2d->loc[0] = loc[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = loc[1] * aspect[1];
td2d->loc2d = loc; /* current location */
}
@@ -6171,8 +6614,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
if (rel) {
if (!anchor) {
- td2d->loc[0] += rel[0] * aspx;
- td2d->loc[1] += rel[1] * aspy;
+ td2d->loc[0] += rel[0] * aspect[0];
+ td2d->loc[1] += rel[1] * aspect[1];
}
copy_v2_v2(tdt->srelative, rel);
@@ -6187,8 +6630,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
//copy_v3_v3(td->center, td->loc);
td->flag |= TD_INDIVIDUAL_SCALE;
- td->center[0] = marker->pos[0] * aspx;
- td->center[1] = marker->pos[1] * aspy;
+ td->center[0] = marker->pos[0] * aspect[0];
+ td->center[1] = marker->pos[1] * aspect[1];
memset(td->axismtx, 0, sizeof(td->axismtx));
td->axismtx[2][2] = 1.0f;
@@ -6203,8 +6646,9 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
unit_m3(td->smtx);
}
-static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d,
- TransDataTracking *tdt, MovieTrackingTrack *track, float aspx, float aspy)
+static void trackToTransData(
+ const int framenr, TransData *td, TransData2D *td2d,
+ TransDataTracking *tdt, MovieTrackingTrack *track, const float aspect[2])
{
MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
@@ -6212,11 +6656,11 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d
marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
- track->offset, marker->pos, track->offset, aspx, aspy);
+ track->offset, marker->pos, track->offset, aspect);
if (track->flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
- marker->pos, NULL, NULL, aspx, aspy);
+ marker->pos, NULL, NULL, aspect);
}
if (track->pat_flag & SELECT) {
@@ -6224,28 +6668,28 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d
for (a = 0; a < 4; a++) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_PAT,
- marker->pattern_corners[a], marker->pos, NULL, aspx, aspy);
+ marker->pattern_corners[a], marker->pos, NULL, aspect);
}
}
if (track->search_flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
- marker->search_min, marker->pos, NULL, aspx, aspy);
+ marker->search_min, marker->pos, NULL, aspect);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
- marker->search_max, marker->pos, NULL, aspx, aspy);
+ marker->search_max, marker->pos, NULL, aspect);
}
}
static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
MovieTrackingPlaneTrack *plane_track, float corner[2],
- float aspx, float aspy)
+ const float aspect[2])
{
tdt->mode = transDataTracking_ModePlaneTracks;
tdt->plane_track = plane_track;
- td2d->loc[0] = corner[0] * aspx; /* hold original location */
- td2d->loc[1] = corner[1] * aspy;
+ td2d->loc[0] = corner[0] * aspect[0]; /* hold original location */
+ td2d->loc[1] = corner[1] * aspect[1];
td2d->loc2d = corner; /* current location */
td2d->loc[2] = 0.0f;
@@ -6270,7 +6714,7 @@ static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDa
static void planeTrackToTransData(const int framenr, TransData *td, TransData2D *td2d,
TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track,
- float aspx, float aspy)
+ const float aspect[2])
{
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
int i;
@@ -6279,7 +6723,7 @@ static void planeTrackToTransData(const int framenr, TransData *td, TransData2D
plane_marker->flag &= ~PLANE_MARKER_TRACKED;
for (i = 0; i < 4; i++) {
- planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspx, aspy);
+ planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
}
}
@@ -6308,7 +6752,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
MovieTrackingPlaneTrack *plane_track;
TransDataTracking *tdt;
int framenr = ED_space_clip_get_clip_frame_number(sc);
- float aspx, aspy;
/* count */
t->total = 0;
@@ -6343,8 +6786,6 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
if (t->total == 0)
return;
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
-
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
tdt = t->customData = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
@@ -6355,7 +6796,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- trackToTransData(framenr, td, td2d, tdt, track, aspx, aspy);
+ trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
/* offset */
td++;
@@ -6389,7 +6830,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
plane_track = plane_track->next)
{
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- planeTrackToTransData(framenr, td, td2d, tdt, plane_track, aspx, aspy);
+ planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
td += 4;
td2d += 4;
tdt += 4;
@@ -6601,14 +7042,10 @@ static void cancelTransTracking(TransInfo *t)
void flushTransTracking(TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
TransData *td;
TransData2D *td2d;
TransDataTracking *tdt;
int a;
- float aspx, aspy;
-
- ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
if (t->state == TRANS_CANCEL)
cancelTransTracking(t);
@@ -6622,8 +7059,8 @@ void flushTransTracking(TransInfo *t)
continue;
}
- loc2d[0] = td2d->loc[0] / aspx;
- loc2d[1] = td2d->loc[1] / aspy;
+ loc2d[0] = td2d->loc[0] / t->aspect[0];
+ loc2d[1] = td2d->loc[1] / t->aspect[1];
if (t->flag & T_ALT_TRANSFORM) {
if (t->mode == TFM_RESIZE) {
@@ -6665,8 +7102,8 @@ void flushTransTracking(TransInfo *t)
td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
}
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
- td2d->loc2d[0] = td2d->loc[0] / aspx;
- td2d->loc2d[1] = td2d->loc[1] / aspy;
+ td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
+ td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
}
}
}
@@ -6744,9 +7181,10 @@ static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which
}
}
-static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
- TransData *td, TransData2D *td2d, TransDataMasking *tdm,
- const int propmode, const float asp[2])
+static void MaskPointToTransData(
+ Scene *scene, MaskSplinePoint *point,
+ TransData *td, TransData2D *td2d, TransDataMasking *tdm,
+ const bool is_prop_edit, const float asp[2])
{
BezTriple *bezt = &point->bezt;
const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
@@ -6756,7 +7194,7 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
invert_m3_m3(parent_inverse_matrix, parent_matrix);
- if (propmode || is_sel_point) {
+ if (is_prop_edit || is_sel_point) {
int i;
tdm->point = point;
@@ -6769,7 +7207,7 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
/* CV coords are scaled by aspects. this is needed for rotations and
* proportional editing to be consistent with the stretched CV coords
* that are displayed. this also means that for display and numinput,
- * and when the the CV coords are flushed, these are converted each time */
+ * and when the CV coords are flushed, these are converted each time */
mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]);
td2d->loc[0] *= asp[0];
td2d->loc[1] *= asp[1];
@@ -6876,7 +7314,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
TransData2D *td2d = NULL;
TransDataMasking *tdm = NULL;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT);
float asp[2];
t->total = 0;
@@ -6926,7 +7364,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
}
}
- if (propmode)
+ if (is_prop_edit)
count += 3;
}
}
@@ -6939,7 +7377,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mask Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -6962,10 +7400,10 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
- if (propmode || MASKPOINT_ISSEL_ANY(point)) {
- MaskPointToTransData(scene, point, td, td2d, tdm, propmode, asp);
+ if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
+ MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
- if (propmode || MASKPOINT_ISSEL_KNOT(point)) {
+ if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
td += 3;
td2d += 3;
tdm += 3;
@@ -7198,6 +7636,246 @@ void flushTransPaintCurve(TransInfo *t)
}
+static void createTransGPencil(bContext *C, TransInfo *t)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+ TransData *td = NULL;
+ float mtx[3][3], smtx[3][3];
+
+ const Scene *scene = CTX_data_scene(C);
+ const int cfra = CFRA;
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+
+
+ /* == Grease Pencil Strokes to Transform Data ==
+ * Grease Pencil stroke points can be a mixture of 2D (screen-space),
+ * or 3D coordinates. However, they're always saved as 3D points.
+ * For now, we just do these without creating TransData2D for the 2D
+ * strokes. This may cause issues in future though.
+ */
+ t->total = 0;
+
+ if (gpd == NULL)
+ return;
+
+ /* First Pass: Count the number of datapoints required for the strokes,
+ * (and additional info about the configuration - e.g. 2D/3D?)
+ */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
+ (gpl->actframe != NULL))
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
+ if (is_prop_edit) {
+ /* Proportional Editing... */
+ if (is_prop_edit_connected) {
+ /* connected only - so only if selected */
+ if (gps->flag & GP_STROKE_SELECT)
+ t->total += gps->totpoints;
+ }
+ else {
+ /* everything goes - connection status doesn't matter */
+ t->total += gps->totpoints;
+ }
+ }
+ else {
+ /* only selected stroke points are considered */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ // TODO: 2D vs 3D?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT)
+ t->total++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Stop trying if nothing selected */
+ if (t->total == 0) {
+ return;
+ }
+
+ /* Allocate memory for data */
+ t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(GPencil)");
+ td = t->data;
+
+ unit_m3(smtx);
+ unit_m3(mtx);
+
+ /* Second Pass: Build transdata array */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
+ (gpl->actframe != NULL))
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
+
+ /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
+ * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
+ * spent too much time editing the wrong frame...
+ */
+ // XXX: should this be allowed when framelock is enabled?
+ if (gpf->framenum != cfra) {
+ bGPDframe *new_frame = gpencil_frame_duplicate(gpf);
+ bGPDframe *gf;
+ bool found = false;
+
+ /* Find frame to insert it before */
+ for (gf = gpf->next; gf; gf = gf->next) {
+ if (gf->framenum > cfra) {
+ /* Add it here */
+ BLI_insertlinkbefore(&gpl->frames, gf, new_frame);
+
+ found = true;
+ break;
+ }
+ else if (gf->framenum == cfra) {
+ /* This only happens when we're editing with framelock on...
+ * - Delete the new frame and don't do anything else here...
+ */
+ //printf("GP Frame convert to TransData - Copy aborted for frame %d -> %d\n", gpf->framenum, gf->framenum);
+ free_gpencil_strokes(new_frame);
+ MEM_freeN(new_frame);
+ new_frame = NULL;
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ /* Add new frame to the end */
+ BLI_addtail(&gpl->frames, new_frame);
+ }
+
+ /* Edit the new frame instead, if it did get created + added */
+ if (new_frame) {
+ // TODO: tag this one as being "newly created" so that we can remove it if the edit is cancelled
+ new_frame->framenum = cfra;
+
+ gpf = new_frame;
+ }
+ }
+
+ /* Loop over strokes, adding TransData for points as needed... */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ TransData *head = td;
+ TransData *tail = td;
+ bool stroke_ok;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
+ /* What we need to include depends on proportional editing settings... */
+ if (is_prop_edit) {
+ if (is_prop_edit_connected) {
+ /* A) "Connected" - Only those in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+ else {
+ /* B) All points, always */
+ stroke_ok = true;
+ }
+ }
+ else {
+ /* C) Only selected points in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+
+ /* Do stroke... */
+ if (stroke_ok && gps->totpoints) {
+ bGPDspoint *pt;
+ int i;
+
+#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */
+ const float ninv = 1.0f / gps->totpoints;
+ float center[3] = {0.0f};
+
+ /* compute midpoint of stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ madd_v3_v3v3fl(center, center, &pt->x, ninv);
+ }
+#endif
+
+ /* add all necessary points... */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bool point_ok;
+
+ /* include point? */
+ if (is_prop_edit) {
+ /* Always all points in strokes that get included */
+ point_ok = true;
+ }
+ else {
+ /* Only selected points in selected strokes */
+ point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
+ }
+
+ /* do point... */
+ if (point_ok) {
+ copy_v3_v3(td->iloc, &pt->x);
+ copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local?
+
+ td->loc = &pt->x;
+
+ td->flag = 0;
+
+ if (pt->flag & GP_SPOINT_SELECT)
+ td->flag |= TD_SELECTED;
+
+ /* for other transform modes (e.g. shrink-fatten), need to additional data */
+ if (t->mode == TFM_GPENCIL_SHRINKFATTEN) {
+ td->val = &pt->pressure;
+ td->ival = pt->pressure;
+ }
+
+ /* configure 2D points so that they don't play up... */
+ if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ // XXX: matrices may need to be different?
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ unit_m3(td->axismtx); // XXX?
+
+ td++;
+ tail++;
+ }
+ }
+
+ /* March over these points, and calculate the proportional editing distances */
+ if (is_prop_edit && (head != tail)) {
+ /* XXX: for now, we are similar enough that this works... */
+ calc_distanceCurveVerts(head, tail - 1);
+ }
+ }
+ }
+ }
+ }
+}
+
+
void createTransData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
@@ -7218,6 +7896,16 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
+ else if (t->options & CTX_GPENCIL_STROKES) {
+ t->flag |= T_POINTS; // XXX...
+ createTransGPencil(C, t);
+
+ if (t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
else if (t->spacetype == SPACE_IMAGE) {
t->flag |= T_POINTS | T_2D_EDIT;
if (t->options & CTX_MASK) {
@@ -7246,6 +7934,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransActionData(C, t);
+
+ if (t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ //set_prop_dist(t, false); /* don't do that, distance has been set in createTransActionData already */
+ sort_trans_data_dist(t);
+ }
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
@@ -7259,13 +7953,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransGraphEditData(C, t);
-#if 0
+
if (t->data && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
- set_prop_dist(t, 1);
+ set_prop_dist(t, false); /* don't do that, distance has been set in createTransGraphEditData already */
sort_trans_data_dist(t);
}
-#endif
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;