Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Mon, 10 Jul 2017 06:35:56 +0000 (16:35 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 10 Jul 2017 06:35:56 +0000 (16:35 +1000)
1  2 
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/intern/curve.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_orientations.c

index 4d55b663f68058aa56b33cf5fd38f936dad2e831,635e999dd9585a524a14be65383c5761a55c19d1..5a65646efe024d570d14a96bb60fc4c1c8fa20f2
@@@ -198,6 -198,7 +198,7 @@@ void BKE_nurb_bezt_calc_normal(struct N
  void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3]);
  
  void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3]);
+ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, struct BPoint *bp, float r_plane[3]);
  
  void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev,  struct BezTriple *next,
                            const bool is_fcurve);
@@@ -219,12 -220,4 +220,12 @@@ void BKE_curve_eval_geometry(struct Eva
  void BKE_curve_eval_path(struct EvaluationContext *eval_ctx,
                           struct Curve *curve);
  
 +/* Draw Cache */
 +enum {
 +      BKE_CURVE_BATCH_DIRTY_ALL = 0,
 +      BKE_CURVE_BATCH_DIRTY_SELECT,
 +};
 +void BKE_curve_batch_cache_dirty(struct Curve *cu, int mode);
 +void BKE_curve_batch_cache_free(struct Curve *cu);
 +
  #endif  /* __BKE_CURVE_H__ */
index 8a6d9f57093b2e37839deb3cefbd390fbc4b2e54,7c22a34c7d14afb976c6f4b5f9ef2b7175225577..2863a9250004b28a3853f73a4b631eef4a7be585
@@@ -52,6 -52,7 +52,6 @@@
  
  #include "BKE_animsys.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_displist.h"
  #include "BKE_font.h"
  #include "BKE_global.h"
@@@ -63,8 -64,6 +63,8 @@@
  #include "BKE_object.h"
  #include "BKE_material.h"
  
 +#include "DEG_depsgraph.h"
 +
  /* globals */
  
  /* local */
@@@ -127,8 -126,6 +127,8 @@@ void BKE_curve_free(Curve *cu
  {
        BKE_animdata_free((ID *)cu, false);
  
 +      BKE_curve_batch_cache_free(cu);
 +
        BKE_nurbList_free(&cu->nurb);
        BKE_curve_editfont_free(cu);
  
@@@ -209,7 -206,6 +209,7 @@@ Curve *BKE_curve_copy(Main *bmain, cons
        cun->strinfo = MEM_dupallocN(cu->strinfo);
        cun->tb = MEM_dupallocN(cu->tb);
        cun->bb = MEM_dupallocN(cu->bb);
 +      cun->batch_cache = NULL;
  
        if (cu->key) {
                cun->key = BKE_key_copy(bmain, cu->key);
@@@ -748,6 -744,7 +748,7 @@@ BezTriple *BKE_nurb_bezt_get_prev(Nurb 
        BezTriple *bezt_prev;
  
        BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
+       BLI_assert(nu->pntsv == 1);
  
        if (bezt == nu->bezt) {
                if (nu->flagu & CU_NURB_CYCLIC) {
@@@ -769,6 -766,7 +770,7 @@@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *
        BPoint *bp_prev;
  
        BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
+       BLI_assert(nu->pntsv == 1);
  
        if (bp == nu->bp) {
                if (nu->flagu & CU_NURB_CYCLIC) {
        return bp_prev;
  }
  
- void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), struct BezTriple *bezt, float r_normal[3])
+ void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), BezTriple *bezt, float r_normal[3])
  {
        /* calculate the axis matrix from the spline */
        float dir_prev[3], dir_next[3];
        normalize_v3(r_normal);
  }
  
- void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3])
+ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, BezTriple *bezt, float r_plane[3])
  {
        float dir_prev[3], dir_next[3];
  
        normalize_v3(r_plane);
  }
  
- void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3])
+ void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, BPoint *bp, float r_normal[3])
  {
        BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
        BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
        normalize_v3(r_normal);
  }
  
+ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
+ {
+       BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+       BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+       float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f};
+       if (bp_prev) {
+               sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
+               normalize_v3(dir_prev);
+       }
+       if (bp_next) {
+               sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
+               normalize_v3(dir_next);
+       }
+       cross_v3_v3v3(r_plane, dir_prev, dir_next);
+       /* matches with bones more closely */
+       {
+               float dir_mid[3], tvec[3];
+               add_v3_v3v3(dir_mid, dir_prev, dir_next);
+               cross_v3_v3v3(tvec, r_plane, dir_mid);
+               copy_v3_v3(r_plane, tvec);
+       }
+       normalize_v3(r_plane);
+ }
  /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
  
  
@@@ -4572,7 -4598,7 +4602,7 @@@ int BKE_curve_material_index_validate(C
        }
  
        if (!is_valid) {
 -              DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
 +              DEG_id_tag_update(&cu->id, OB_RECALC_DATA);
                return true;
        }
        else {
@@@ -4660,20 -4686,3 +4690,20 @@@ void BKE_curve_eval_path(EvaluationCont
                printf("%s on %s\n", __func__, curve->id.name);
        }
  }
 +
 +/* Draw Engine */
 +void (*BKE_curve_batch_cache_dirty_cb)(Curve *cu, int mode) = NULL;
 +void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
 +
 +void BKE_curve_batch_cache_dirty(Curve *cu, int mode)
 +{
 +      if (cu->batch_cache) {
 +              BKE_curve_batch_cache_dirty_cb(cu, mode);
 +      }
 +}
 +void BKE_curve_batch_cache_free(Curve *cu)
 +{
 +      if (cu->batch_cache) {
 +              BKE_curve_batch_cache_free_cb(cu);
 +      }
 +}
index 5b48f4326e85a5ae3570ae5da43442947bb8e8e2,4429d19613a4339a64371f201afd6ce9003f024e..6f17a15c334a6fd1f049d7081b66eb6ae34a2adb
  #include "BKE_context.h"
  #include "BKE_crazyspace.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_fcurve.h"
  #include "BKE_global.h"
  #include "BKE_gpencil.h"
 +#include "BKE_layer.h"
  #include "BKE_key.h"
  #include "BKE_main.h"
  #include "BKE_mesh.h"
  #include "RNA_access.h"
  
  #include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
  
  #include "transform.h"
  #include "bmesh.h"
@@@ -286,13 -285,13 +286,13 @@@ static void set_prop_dist(TransInfo *t
  
  static void createTransTexspace(TransInfo *t)
  {
 -      Scene *scene = t->scene;
 +      SceneLayer *sl = t->scene_layer;
        TransData *td;
        Object *ob;
        ID *id;
        short *texflag;
  
 -      ob = OBACT;
 +      ob = OBACT_NEW;
  
        if (ob == NULL) { // Shouldn't logically happen, but still...
                t->total = 0;
@@@ -837,9 -836,14 +837,9 @@@ void transform_autoik_update(TransInfo 
                changed |= pchan_autoik_adjust(pchan, *chainlen);
        }
  
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!DEG_depsgraph_use_legacy())
 -#endif
 -      {
 -              if (changed) {
 -                      /* TODO(sergey): Consider doing partial update only. */
 -                      DAG_relations_tag_update(G.main);
 -              }
 +      if (changed) {
 +              /* TODO(sergey): Consider doing partial update only. */
 +              DEG_relations_tag_update(G.main);
        }
  }
  
@@@ -849,6 -853,9 +849,6 @@@ static void pose_grab_with_ik_clear(Obj
        bKinematicConstraint *data;
        bPoseChannel *pchan;
        bConstraint *con, *next;
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      bool need_dependency_update = false;
 -#endif
  
        for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
                /* clear all temporary lock flags */
                                data = con->data;
                                if (data->flag & CONSTRAINT_IK_TEMP) {
                                        /* iTaSC needs clear for removed constraints */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -                                      need_dependency_update = true;
 -#endif
                                        BIK_clear_data(ob->pose);
  
                                        BLI_remlink(&pchan->constraints, con);
                }
        }
  
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!DEG_depsgraph_use_legacy() && need_dependency_update)
 -#endif
 -      {
 -              /* TODO(sergey): Consider doing partial update only. */
 -              DAG_relations_tag_update(G.main);
 -      }
 +      /* TODO(sergey): Consider doing partial update only. */
 +      DEG_relations_tag_update(G.main);
  }
  
  /* adds the IK to pchan - returns if added */
@@@ -1031,8 -1046,13 +1031,8 @@@ static short pose_grab_with_ik(Object *
        /* iTaSC needs clear for new IK constraints */
        if (tot_ik) {
                BIK_clear_data(ob->pose);
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -              if (!DEG_depsgraph_use_legacy())
 -#endif
 -              {
 -                      /* TODO(sergey): Consuder doing partial update only. */
 -                      DAG_relations_tag_update(G.main);
 -              }
 +              /* TODO(sergey): Consuder doing partial update only. */
 +              DEG_relations_tag_update(G.main);
        }
  
        return (tot_ik) ? 1 : 0;
@@@ -1505,6 -1525,48 +1505,48 @@@ static TransDataCurveHandleFlags *initT
        return hdata;
  }
  
+ /**
+  * For the purpose of transform code we need to behave as if handles are selected,
+  * even when they aren't (see special case below).
+  */
+ static int bezt_select_to_transform_triple_flag(
+         const BezTriple *bezt, const bool hide_handles)
+ {
+       int flag = 0;
+       if (hide_handles) {
+               if (bezt->f2 & SELECT) {
+                       flag = (1 << 0) | (1 << 1) | (1 << 2);
+               }
+       }
+       else {
+               flag = (
+                       ((bezt->f1 & SELECT) ? (1 << 0) : 0) |
+                       ((bezt->f2 & SELECT) ? (1 << 1) : 0) |
+                       ((bezt->f3 & SELECT) ? (1 << 2) : 0)
+               );
+       }
+       /* Special case for auto & aligned handles:
+        * When a center point is being moved without the handles,
+        * leaving the handles stationary makes no sense and only causes strange behavior,
+        * where one handle is arbitrarily anchored, the other one is aligned and lengthened
+        * based on where the center point is moved. Also a bug when cancelling, see: T52007.
+        *
+        * A more 'correct' solution could be to store handle locations in 'TransDataCurveHandleFlags'.
+        * However that doesn't resolve odd behavior, so best transform the handles in this case.
+        */
+       if ((flag != ((1 << 0) | (1 << 1) | (1 << 2))) && (flag & (1 << 1))) {
+               if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) &&
+                   ELEM(bezt->h2, HD_AUTO, HD_ALIGN))
+               {
+                       flag = (1 << 0) | (1 << 1) | (1 << 2);
+               }
+       }
+       return flag;
+ }
  static void createTransCurveVerts(TransInfo *t)
  {
        Curve *cu = t->obedit->data;
        /* to be sure */
        if (cu->editnurb == NULL) return;
  
+ #define SEL_F1 (1 << 0)
+ #define SEL_F2 (1 << 1)
+ #define SEL_F3 (1 << 2)
        /* count total of vertices, check identical as in 2nd loop for making transdata! */
        nurbs = BKE_curve_editNurbs_get(cu);
        for (nu = nurbs->first; nu; nu = nu->next) {
                if (nu->type == CU_BEZIER) {
                        for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
                                if (bezt->hide == 0) {
-                                       if (hide_handles) {
-                                               if (bezt->f2 & SELECT) countsel += 3;
-                                               if (is_prop_edit) count += 3;
-                                       }
-                                       else {
-                                               if (bezt->f1 & SELECT) countsel++;
-                                               if (bezt->f2 & SELECT) countsel++;
-                                               if (bezt->f3 & SELECT) countsel++;
-                                               if (is_prop_edit) count += 3;
-                                       }
+                                       const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+                                       if (bezt_tx & SEL_F1) { countsel++; }
+                                       if (bezt_tx & SEL_F2) { countsel++; }
+                                       if (bezt_tx & SEL_F3) { countsel++; }
+                                       if (is_prop_edit) count += 3;
                                }
                        }
                }
                                                }
                                        }
  
-                                       if (is_prop_edit ||
-                                           ((bezt->f2 & SELECT) && hide_handles) ||
-                                           ((bezt->f1 & SELECT) && hide_handles == 0))
-                                       {
+                                       /* Elements that will be transform (not always a match to selection). */
+                                       const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+                                       if (is_prop_edit || bezt_tx & SEL_F1) {
                                                copy_v3_v3(td->iloc, bezt->vec[0]);
                                                td->loc = bezt->vec[0];
                                                copy_v3_v3(td->center, bezt->vec[(hide_handles ||
                                        }
  
                                        /* This is the Curve Point, the other two are handles */
-                                       if (is_prop_edit || (bezt->f2 & SELECT)) {
+                                       if (is_prop_edit || bezt_tx & SEL_F2) {
                                                copy_v3_v3(td->iloc, bezt->vec[1]);
                                                td->loc = bezt->vec[1];
                                                copy_v3_v3(td->center, td->loc);
                                                        copy_m3_m3(td->axismtx, axismtx);
                                                }
  
-                                               if ((bezt->f1 & SELECT) == 0 && (bezt->f3 & SELECT) == 0)
+                                               if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0)
                                                        /* If the middle is selected but the sides arnt, this is needed */
                                                        if (hdata == NULL) { /* if the handle was not saved by the previous handle */
                                                                hdata = initTransDataCurveHandles(td, bezt);
                                                count++;
                                                tail++;
                                        }
-                                       if (is_prop_edit ||
-                                           ((bezt->f2 & SELECT) && hide_handles) ||
-                                           ((bezt->f3 & SELECT) && hide_handles == 0))
-                                       {
+                                       if (is_prop_edit || bezt_tx & SEL_F3) {
                                                copy_v3_v3(td->iloc, bezt->vec[2]);
                                                td->loc = bezt->vec[2];
                                                copy_v3_v3(td->center, bezt->vec[(hide_handles ||
                        for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
                                if (bp->hide == 0) {
                                        if (is_prop_edit || (bp->f1 & SELECT)) {
+                                               float axismtx[3][3];
+                                               if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+                                                       if (nu->pntsv == 1) {
+                                                               float normal[3], plane[3];
+                                                               BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+                                                               BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+                                                               if (createSpaceNormalTangent(axismtx, normal, plane)) {
+                                                                       /* pass */
+                                                               }
+                                                               else {
+                                                                       normalize_v3(normal);
+                                                                       axis_dominant_v3_to_m3(axismtx, normal);
+                                                                       invert_m3(axismtx);
+                                                               }
+                                                       }
+                                               }
                                                copy_v3_v3(td->iloc, bp->vec);
                                                td->loc = bp->vec;
                                                copy_v3_v3(td->center, td->loc);
  
                                                copy_m3_m3(td->smtx, smtx);
                                                copy_m3_m3(td->mtx, mtx);
+                                               if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+                                                       if (nu->pntsv == 1) {
+                                                               copy_m3_m3(td->axismtx, axismtx);
+                                                       }
+                                               }
  
                                                td++;
                                                count++;
                                calc_distanceCurveVerts(head, tail - 1);
                }
        }
+ #undef SEL_F1
+ #undef SEL_F2
+ #undef SEL_F3
  }
  
  /* ********************* lattice *************** */
@@@ -1820,7 -1908,7 +1888,7 @@@ static void createTransParticleVerts(bC
        Base *base = CTX_data_active_base(C);
        Object *ob = CTX_data_active_object(C);
        ParticleEditSettings *pset = PE_settings(t->scene);
 -      PTCacheEdit *edit = PE_get_current(t->scene, ob);
 +      PTCacheEdit *edit = PE_get_current(t->scene, t->scene_layer, ob);
        ParticleSystem *psys = NULL;
        ParticleSystemModifierData *psmd = NULL;
        PTCacheEditPoint *point;
  void flushTransParticles(TransInfo *t)
  {
        Scene *scene = t->scene;
 -      Object *ob = OBACT;
 -      PTCacheEdit *edit = PE_get_current(scene, ob);
 +      SceneLayer *sl = t->scene_layer;
 +      Object *ob = OBACT_NEW;
 +      PTCacheEdit *edit = PE_get_current(scene, sl, ob);
        ParticleSystem *psys = edit->psys;
        ParticleSystemModifierData *psmd = NULL;
        PTCacheEditPoint *point;
                        point->flag |= PEP_EDIT_RECALC;
        }
  
 -      PE_update_object(scene, OBACT, 1);
 +      PE_update_object(scene, sl, OBACT_NEW, 1);
  }
  
  /* ********************* mesh ****************** */
@@@ -2873,6 -2960,7 +2941,6 @@@ static void createTransUVs(bContext *C
        const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
        const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
        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;
        }
  
        BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 -              MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
                BMLoop *l;
  
 -              if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
 +              if (!uvedit_face_visible_test(scene, ima, efa)) {
                        BM_elem_flag_disable(efa, BM_ELEM_TAG);
                        continue;
                }
@@@ -5453,11 -5542,12 +5521,11 @@@ static void ObjectToTransData(TransInf
  /* it deselects Bases, so we have to call the clear function always after */
  static void set_trans_object_base_flags(TransInfo *t)
  {
 -      Scene *scene = t->scene;
 -      View3D *v3d = t->view;
 +      SceneLayer *sl = t->scene_layer;
  
        /*
         * if Base selected and has parent selected:
 -       * base->flag = BA_WAS_SEL
 +       * base->flag_legacy = BA_WAS_SEL
         */
        Base *base;
  
                return;
  
        /* makes sure base flags and object flags are identical */
 -      BKE_scene_base_flag_to_objects(t->scene);
 +      BKE_scene_base_flag_to_objects(t->scene_layer);
  
        /* Make sure depsgraph is here. */
 -      DAG_scene_relations_update(G.main, t->scene);
 +      DEG_scene_relations_update(G.main, t->scene);
  
        /* handle pending update events, otherwise they got copied below */
 -      for (base = scene->base.first; base; base = base->next) {
 +      for (base = sl->object_bases.first; base; base = base->next) {
                if (base->object->recalc & OB_RECALC_ALL) {
                        /* TODO(sergey): Ideally, it's not needed. */
                        BKE_object_handle_update(G.main->eval_ctx, t->scene, base->object);
                }
        }
  
 -      for (base = scene->base.first; base; base = base->next) {
 -              base->flag &= ~BA_WAS_SEL;
 +      for (base = sl->object_bases.first; base; base = base->next) {
 +              base->flag_legacy &= ~BA_WAS_SEL;
  
 -              if (TESTBASELIB_BGMODE(v3d, scene, base)) {
 +              if (TESTBASELIB_BGMODE_NEW(base)) {
                        Object *ob = base->object;
                        Object *parsel = ob->parent;
  
                        /* if parent selected, deselect */
                        while (parsel) {
 -                              if (parsel->flag & SELECT) {
 -                                      Base *parbase = BKE_scene_base_find(scene, parsel);
 +                              if (parsel->base_flag & BASE_SELECTED) {
 +                                      Base *parbase = BKE_scene_layer_base_find(sl, parsel);
                                        if (parbase) { /* in rare cases this can fail */
 -                                              if (TESTBASELIB_BGMODE(v3d, scene, parbase)) {
 +                                              if (TESTBASELIB_BGMODE_NEW(parbase)) {
                                                        break;
                                                }
                                        }
                                if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
                                    (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))
                                {
 -                                      base->flag |= BA_TRANSFORM_CHILD;
 +                                      base->flag_legacy |= BA_TRANSFORM_CHILD;
                                }
                                else {
 -                                      base->flag &= ~SELECT;
 -                                      base->flag |= BA_WAS_SEL;
 +                                      base->flag &= ~BASE_SELECTED;
 +                                      base->flag_legacy |= BA_WAS_SEL;
                                }
                        }
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_OB);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_OB);
                }
        }
  
 -      /* 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 */
 -      for (base = scene->base.first; base; base = base->next) {
 +      for (base = sl->object_bases.first; base; base = base->next) {
                if (base->object->recalc & OB_RECALC_OB)
 -                      base->flag |= BA_HAS_RECALC_OB;
 +                      base->flag_legacy |= BA_HAS_RECALC_OB;
                if (base->object->recalc & OB_RECALC_DATA)
 -                      base->flag |= BA_HAS_RECALC_DATA;
 +                      base->flag_legacy |= BA_HAS_RECALC_DATA;
        }
  }
  
@@@ -5543,7 -5638,8 +5611,7 @@@ static bool mark_children(Object *ob
  static int count_proportional_objects(TransInfo *t)
  {
        int total = 0;
 -      Scene *scene = t->scene;
 -      View3D *v3d = t->view;
 +      SceneLayer *sl = t->scene_layer;
        Base *base;
  
        /* rotations around local centers are allowed to propagate, so we take all objects */
              (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)))
        {
                /* mark all parents */
 -              for (base = scene->base.first; base; base = base->next) {
 -                      if (TESTBASELIB_BGMODE(v3d, scene, base)) {
 +              for (base = sl->object_bases.first; base; base = base->next) {
 +                      if (TESTBASELIB_BGMODE_NEW(base)) {
                                Object *parent = base->object->parent;
        
                                /* flag all parents */
                }
  
                /* mark all children */
 -              for (base = scene->base.first; base; base = base->next) {
 +              for (base = sl->object_bases.first; base; base = base->next) {
                        /* all base not already selected or marked that is editable */
 -                      if ((base->object->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
 -                          (BASE_EDITABLE_BGMODE(v3d, scene, base)))
 +                      if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
 +                          (base->flag & BASE_SELECTED) == 0 &&
 +                          (BASE_EDITABLE_BGMODE_NEW(base)))
                        {
                                mark_children(base->object);
                        }
                }
        }
        
 -      for (base = scene->base.first; base; base = base->next) {
 +      for (base = sl->object_bases.first; base; base = base->next) {
                Object *ob = base->object;
  
                /* if base is not selected, not a parent of selection or not a child of selection and it is editable */
 -              if ((ob->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
 -                  (BASE_EDITABLE_BGMODE(v3d, scene, base)))
 +              if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
 +                  (base->flag & BASE_SELECTED) == 0 &&
 +                  (BASE_EDITABLE_BGMODE_NEW(base)))
                {
  
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_OB);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_OB);
  
                        total += 1;
                }
        
  
        /* 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
 +      DEG_scene_relations_update(G.main, t->scene);
  
        /* and we store them temporal in base (only used for transform code) */
        /* this because after doing updates, the object->recalc is cleared */
 -      for (base = scene->base.first; base; base = base->next) {
 +      for (base = sl->object_bases.first; base; base = base->next) {
                if (base->object->recalc & OB_RECALC_OB)
 -                      base->flag |= BA_HAS_RECALC_OB;
 +                      base->flag_legacy |= BA_HAS_RECALC_OB;
                if (base->object->recalc & OB_RECALC_DATA)
 -                      base->flag |= BA_HAS_RECALC_DATA;
 +                      base->flag_legacy |= BA_HAS_RECALC_DATA;
        }
  
        return total;
  
  static void clear_trans_object_base_flags(TransInfo *t)
  {
 -      Scene *sce = t->scene;
 +      SceneLayer *sl = t->scene_layer;
        Base *base;
  
 -      for (base = sce->base.first; base; base = base->next) {
 -              if (base->flag & BA_WAS_SEL)
 -                      base->flag |= SELECT;
 +      for (base = sl->object_bases.first; base; base = base->next) {
 +              if (base->flag_legacy & BA_WAS_SEL) {
 +                      base->flag |= BASE_SELECTED;
 +              }
  
 -              base->flag &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
 +              base->flag_legacy &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
        }
  }
  
   *  tmode: should be 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
 -void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode)
 +void autokeyframe_ob_cb_func(bContext *C, Scene *scene, SceneLayer *sl, View3D *v3d, Object *ob, int tmode)
  {
        ID *id = &ob->id;
        FCurve *fcu;
                        }
                        else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
                                if (v3d->around == V3D_AROUND_ACTIVE) {
 -                                      if (ob != OBACT)
 +                                      if (ob != OBACT_NEW)
                                                do_loc = true;
                                }
                                else if (v3d->around == V3D_AROUND_CURSOR)
                        }
                        else if (tmode == TFM_RESIZE) {
                                if (v3d->around == V3D_AROUND_ACTIVE) {
 -                                      if (ob != OBACT)
 +                                      if (ob != OBACT_NEW)
                                                do_loc = true;
                                }
                                else if (v3d->around == V3D_AROUND_CURSOR)
@@@ -6177,9 -6273,9 +6245,9 @@@ void special_aftertrans_update(bContex
                        // fixme... some of this stuff is not good
                        if (ob) {
                                if (ob->pose || BKE_key_from_object(ob))
 -                                      DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
 +                                      DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
                                else
 -                                      DAG_id_tag_update(&ob->id, OB_RECALC_OB);
 +                                      DEG_id_tag_update(&ob->id, OB_RECALC_OB);
                        }
                        
                        /* 3 cases here for curve cleanups:
                /* automatic inserting of keys and unkeyed tagging - only if transform wasn't canceled (or TFM_DUMMY) */
                if (!canceled && (t->mode != TFM_DUMMY)) {
                        autokeyframe_pose_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                }
                else if (arm->flag & ARM_DELAYDEFORM) {
                        /* old optimize trick... this enforces to bypass the depgraph */
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                        ob->recalc = 0;  // is set on OK position already by recalcData()
                }
                else
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
  
        }
        else if (t->options & CTX_PAINT_CURVE) {
                /* pass */
        }
 -      else if ((t->scene->basact) &&
 -               (ob = t->scene->basact->object) &&
 +      else if ((t->scene_layer->basact) &&
 +               (ob = t->scene_layer->basact->object) &&
                 (ob->mode & OB_MODE_PARTICLE_EDIT) &&
 -               PE_get_current(t->scene, ob))
 +               PE_get_current(t->scene, t->scene_layer, ob))
        {
                /* do nothing */
        }
  
                        /* pointcache refresh */
                        if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED))
 -                              DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +                              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
  
                        /* 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 */
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_OB);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_OB);
  
                        /* Set autokey if necessary */
                        if (!canceled) {
 -                              autokeyframe_ob_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode);
 +                              autokeyframe_ob_cb_func(C, t->scene, t->scene_layer, (View3D *)t->view, ob, t->mode);
                        }
                        
                        /* restore rigid body transform */
@@@ -6482,6 -6578,8 +6550,6 @@@ int special_transform_moving(TransInfo 
  
  static void createTransObject(bContext *C, TransInfo *t)
  {
 -      Scene *scene = t->scene;
 -
        TransData *td = NULL;
        TransDataExtension *tx;
        const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
        CTX_DATA_END;
        
        if (is_prop_edit) {
 -              View3D *v3d = t->view;
 +              SceneLayer *sl = t->scene_layer;
                Base *base;
  
 -              for (base = scene->base.first; base; base = base->next) {
 +              for (base = sl->object_bases.first; base; base = base->next) {
                        Object *ob = base->object;
  
                        /* if base is not selected, not a parent of selection or not a child of selection and it is editable */
 -                      if ((ob->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
 -                          BASE_EDITABLE_BGMODE(v3d, scene, base))
 +                      if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
 +                          (base->flag & BASE_SELECTED) == 0 &&
 +                          BASE_EDITABLE_BGMODE_NEW(base))
                        {
                                td->protectflag = ob->protectflag;
                                td->ext = tx;
@@@ -7987,8 -8084,7 +8055,8 @@@ static void createTransGPencil(bContex
  void createTransData(bContext *C, TransInfo *t)
  {
        Scene *scene = t->scene;
 -      Object *ob = OBACT;
 +      SceneLayer *sl = t->scene_layer;
 +      Object *ob = OBACT_NEW;
  
        /* if tests must match recalcData for correct updates */
        if (t->options & CTX_TEXTURE) {
                 * lines below just check is also visible */
                Object *ob_armature = modifiers_isDeformedByArmature(ob);
                if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
 -                      Base *base_arm = BKE_scene_base_find(t->scene, ob_armature);
 +                      Base *base_arm = BKE_scene_layer_base_find(t->scene_layer, ob_armature);
                        if (base_arm) {
 -                              View3D *v3d = t->view;
 -                              if (BASE_VISIBLE(v3d, base_arm)) {
 +                              if (BASE_VISIBLE_NEW(base_arm)) {
                                        createTransPose(t, ob_armature);
                                }
                        }
                        
                }
        }
 -      else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
 +      else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, sl, ob))) {
                createTransParticleVerts(C, t);
                t->flag |= T_POINTS;
  
index c0db83ffa5e90df5dc1d87cb42046dca37567b62,54959304d72086bc9f20406debd98507f992d45d..21d071b1f8de0ff3e1860f642572bf837ad7e7f8
@@@ -38,7 -38,6 +38,7 @@@
  #include "DNA_screen_types.h"
  #include "DNA_space_types.h"
  #include "DNA_view3d_types.h"
 +#include "DNA_workspace_types.h"
  
  #include "BLI_math.h"
  #include "BLI_listbase.h"
@@@ -53,7 -52,6 +53,7 @@@
  #include "BKE_report.h"
  #include "BKE_main.h"
  #include "BKE_screen.h"
 +#include "BKE_workspace.h"
  
  #include "BLT_translation.h"
  
  
  void BIF_clearTransformOrientation(bContext *C)
  {
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace);
        View3D *v3d = CTX_wm_view3d(C);
  
 -      ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
 -      BLI_freelistN(transform_spaces);
 +      BLI_freelistN(transform_orientations);
        
        // Need to loop over all view3d
 -      if (v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
 -              v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
 +      if (v3d && v3d->twmode == V3D_MANIP_CUSTOM) {
 +              v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
 +              v3d->custom_orientation_index = -1;
        }
  }
  
@@@ -322,24 -318,23 +322,24 @@@ void BIF_createTransformOrientation(bCo
  TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3],
                                       const char *name, const bool overwrite)
  {
 -      ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
        TransformOrientation *ts = NULL;
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace);
        char name_unique[sizeof(ts->name)];
  
        if (overwrite) {
 -              ts = findOrientationName(transform_spaces, name);
 +              ts = findOrientationName(transform_orientations, name);
        }
        else {
                BLI_strncpy(name_unique, name, sizeof(name_unique));
 -              uniqueOrientationName(transform_spaces, name_unique);
 +              uniqueOrientationName(transform_orientations, name_unique);
                name = name_unique;
        }
  
        /* if not, create a new one */
        if (ts == NULL) {
                ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
 -              BLI_addtail(transform_spaces, ts);
 +              BLI_addtail(transform_orientations, ts);
                BLI_strncpy(ts->name, name, sizeof(ts->name));
        }
  
  
  void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target)
  {
 -      Scene *scene = CTX_data_scene(C);
 -      ListBase *transform_spaces = &scene->transform_spaces;
 -      const int i = BLI_findindex(transform_spaces, target);
 -
 -      if (i != -1) {
 -              Main *bmain = CTX_data_main(C);
 -              BKE_screen_view3d_main_twmode_remove(&bmain->screen, scene, i);
 -              BLI_freelinkN(transform_spaces, target);
 -      }
 +      BKE_workspace_transform_orientation_remove(CTX_wm_workspace(C), target);
  }
  
  void BIF_removeTransformOrientationIndex(bContext *C, int index)
  {
 -      ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
 -      TransformOrientation *ts = BLI_findlink(transform_spaces, index);
 -
 -      if (ts) {
 -              BIF_removeTransformOrientation(C, ts);
 -      }
 +      TransformOrientation *target = BKE_workspace_transform_orientation_find(CTX_wm_workspace(C), index);
 +      BIF_removeTransformOrientation(C, target);
  }
  
  void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target)
  {
 -      ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
 -      const int i = BLI_findindex(transform_spaces, target);
 +      int index = BKE_workspace_transform_orientation_get_index(CTX_wm_workspace(C), target);
 +      View3D *v3d = CTX_wm_view3d(C);
  
 -      if (i != -1) {
 -              View3D *v3d = CTX_wm_view3d(C);
 -              v3d->twmode = V3D_MANIP_CUSTOM + i;
 -      }
 +      BLI_assert(index != -1);
 +
 +      v3d->twmode = V3D_MANIP_CUSTOM;
 +      v3d->custom_orientation_index = index;
  }
  
 -void BIF_selectTransformOrientationValue(bContext *C, int orientation)
 +/**
 + * Activate a transform orientation in a 3D view based on an enum value.
 + *
 + * \param orientation: If this is #V3D_MANIP_CUSTOM or greater, the custom transform orientation
 + *                     with index \a orientation - #V3D_MANIP_CUSTOM gets activated.
 + */
 +void BIF_selectTransformOrientationValue(View3D *v3d, int orientation)
  {
 -      View3D *v3d = CTX_wm_view3d(C);
 -      if (v3d) /* currently using generic poll */
 -              v3d->twmode = orientation;
 +      const bool is_custom = orientation >= V3D_MANIP_CUSTOM;
 +
 +      v3d->twmode = is_custom ? V3D_MANIP_CUSTOM : orientation;
 +      v3d->custom_orientation_index = is_custom ? (orientation - V3D_MANIP_CUSTOM) : -1;
  }
  
  int BIF_countTransformOrientation(const bContext *C)
  {
 -      ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
 -      return BLI_listbase_count(transform_spaces);
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace);
 +      return BLI_listbase_count(transform_orientations);
  }
  
 -bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name, int index)
 +bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name)
  {
 -      ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
 -      TransformOrientation *ts = BLI_findlink(transform_spaces, index);
 -
 -      BLI_assert(index >= 0);
 -
 -      if (ts) {
 -              if (r_name) {
 -                      BLI_strncpy(r_name, ts->name, MAX_NAME);
 -              }
 -
 -              copy_m3_m3(mat, ts->mat);
 -              return true;
 -      }
 -      else {
 -              /* invalid index, can happen sometimes */
 -              return false;
 +      if (r_name) {
 +              BLI_strncpy(r_name, ts->name, MAX_NAME);
        }
 +      copy_m3_m3(r_mat, ts->mat);
 +
 +      return true;
  }
  
  static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
@@@ -482,10 -492,8 +482,10 @@@ void initTransformOrientation(bContext 
                                unit_m3(t->spacemtx);
                        }
                        break;
 -              default: /* V3D_MANIP_CUSTOM */
 -                      if (applyTransformOrientation(C, t->spacemtx, t->spacename, t->current_orientation - V3D_MANIP_CUSTOM)) {
 +              case V3D_MANIP_CUSTOM:
 +                      BLI_strncpy(t->spacename, t->custom_orientation->name, sizeof(t->spacename));
 +
 +                      if (applyTransformOrientation(t->custom_orientation, t->spacemtx, t->spacename)) {
                                /* pass */
                        }
                        else {
@@@ -578,10 -586,10 +578,10 @@@ static unsigned int bm_mesh_faces_selec
  
  int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3], const short around)
  {
 -      Scene *scene = CTX_data_scene(C);
 +      SceneLayer *sl = CTX_data_scene_layer(C);
        Object *obedit = CTX_data_edit_object(C);
        Base *base;
 -      Object *ob = OBACT;
 +      Object *ob = OBACT_NEW;
        int result = ORIENTATION_NONE;
        const bool activeOnly = (around == V3D_AROUND_ACTIVE);
  
                else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
                        Curve *cu = obedit->data;
                        Nurb *nu = NULL;
-                       BezTriple *bezt = NULL;
                        int a;
                        ListBase *nurbs = BKE_curve_editNurbs_get(cu);
  
-                       if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bezt)) {
+                       void *vert_act = NULL;
+                       if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, &vert_act)) {
                                if (nu->type == CU_BEZIER) {
+                                       BezTriple *bezt = vert_act;
                                        BKE_nurb_bezt_calc_normal(nu, bezt, normal);
                                        BKE_nurb_bezt_calc_plane(nu, bezt, plane);
                                }
+                               else {
+                                       BPoint *bp = vert_act;
+                                       BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+                                       BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+                               }
                        }
                        else {
                                const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0;
                                for (nu = nurbs->first; nu; nu = nu->next) {
                                        /* only bezier has a normal */
                                        if (nu->type == CU_BEZIER) {
-                                               bezt = nu->bezt;
+                                               BezTriple *bezt = nu->bezt;
                                                a = nu->pntsu;
                                                while (a--) {
                                                        short flag = 0;
                                                        bezt++;
                                                }
                                        }
+                                       else if (nu->bp && (nu->pntsv == 1)) {
+                                               BPoint *bp = nu->bp;
+                                               a = nu->pntsu;
+                                               while (a--) {
+                                                       if (bp->f1 & SELECT) {
+                                                               float tvec[3];
+                                                               BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+                                                               BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+                                                               const bool is_prev_sel = bp_prev && (bp_prev->f1 & SELECT);
+                                                               const bool is_next_sel = bp_next && (bp_next->f1 & SELECT);
+                                                               if (is_prev_sel == false && is_next_sel == false) {
+                                                                       /* Isolated, add based on surrounding */
+                                                                       BKE_nurb_bpoint_calc_normal(nu, bp, tvec);
+                                                                       add_v3_v3(normal, tvec);
+                                                               }
+                                                               else if (is_next_sel) {
+                                                                       /* A segment, add the edge normal */
+                                                                       sub_v3_v3v3(tvec, bp->vec, bp_next->vec );
+                                                                       normalize_v3(tvec);
+                                                                       add_v3_v3(normal, tvec);
+                                                               }
+                                                               BKE_nurb_bpoint_calc_plane(nu, bp, tvec);
+                                                               add_v3_v3(plane, tvec);
+                                                       }
+                                                       bp++;
+                                               }
+                                       }
                                }
                        }
                        
        }
        else {
                /* we need the one selected object, if its not active */
 -              View3D *v3d = CTX_wm_view3d(C);
 -              ob = OBACT;
 -              if (ob && (ob->flag & SELECT)) {
 +              base = BASACT_NEW;
 +              ob = OBACT_NEW;
 +              if (base && ((base->flag & BASE_SELECTED) != 0)) {
                        /* pass */
                }
                else {
                        /* first selected */
                        ob = NULL;
 -                      for (base = scene->base.first; base; base = base->next) {
 -                              if (TESTBASELIB(v3d, base)) {
 +                      for (base = sl->object_bases.first; base; base = base->next) {
 +                              if (TESTBASELIB_NEW(base)) {
                                        ob = base->object;
                                        break;
                                }