Proportional edit for object mode.
[blender.git] / source / blender / editors / transform / transform_conversions.c
index 0ff0e400d26ecc66d5a3485d3c4f17c111b55385..449994f2cec5761188adde5c58758fd2ca84d5c4 100644 (file)
@@ -4314,7 +4314,7 @@ static void ObjectToTransData(bContext *C, TransInfo *t, TransData *td, Object *
 /* it deselects Bases, so we have to call the clear function always after */
 static void set_trans_object_base_flags(bContext *C, TransInfo *t)
 {
-       Scene *scene = CTX_data_scene(C);
+       Scene *scene = t->scene;
        View3D *v3d = t->view;
 
        /*
@@ -4339,7 +4339,7 @@ static void set_trans_object_base_flags(bContext *C, TransInfo *t)
        for (base= scene->base.first; base; base= base->next) {
                base->flag &= ~BA_WAS_SEL;
 
-               if(TESTBASELIB_BGMODE(v3d, base)) {
+               if(TESTBASELIB_BGMODE(v3d, scene, base)) {
                        Object *ob= base->object;
                        Object *parsel= ob->parent;
 
@@ -4351,12 +4351,10 @@ static void set_trans_object_base_flags(bContext *C, TransInfo *t)
 
                        if(parsel)
                        {
-                               if ((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)  && t->around == V3D_LOCAL)
-                               {
+                               /* rotation around local centers are allowed to propagate */
+                               if ((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)  && t->around == V3D_LOCAL) {
                                        base->flag |= BA_TRANSFORM_CHILD;
-                               }
-                               else
-                               {
+                               } else {
                                        base->flag &= ~SELECT;
                                        base->flag |= BA_WAS_SEL;
                                }
@@ -4379,6 +4377,86 @@ static void set_trans_object_base_flags(bContext *C, TransInfo *t)
        }
 }
 
+static int mark_children(Object *ob)
+{
+       if (ob->flag & (SELECT|BA_TRANSFORM_CHILD))
+               return 1;
+
+       if (ob->parent)
+       {
+               if (mark_children(ob->parent))
+               {
+                       ob->flag |= BA_TRANSFORM_CHILD;
+                       return 1;
+               }
+       }
+       
+       return 0;
+}
+
+static int count_proportional_objects(TransInfo *t)
+{
+       int total = 0;
+       Scene *scene = t->scene;
+       View3D *v3d = t->view;
+       Base *base;
+
+       /* rotations around local centers are allowed to propagate, so we take all objects */
+       if (!((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)  && t->around == V3D_LOCAL))
+       {
+               /* mark all parents */
+               for (base= scene->base.first; base; base= base->next) {
+                       if(TESTBASELIB_BGMODE(v3d, scene, base)) {
+                               Object *parent = base->object->parent;
+       
+                               /* flag all parents */
+                               while(parent) {
+                                       parent->flag |= BA_TRANSFORM_PARENT;
+                                       parent = parent->parent;
+                               }
+                       }
+               }
+
+               /* mark all children */
+               for (base= scene->base.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))
+                       {
+                               mark_children(base->object);
+                       }
+               }
+       }
+       
+       for (base= scene->base.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))
+               {
+
+                       /* used for flush, depgraph will change recalcs if needed :) */
+                       ob->recalc |= OB_RECALC_OB;
+
+                       total += 1;
+               }
+       }
+       
+
+       /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
+       DAG_scene_flush_update(t->scene, -1, 0);
+
+       /* 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) {
+               if(base->object->recalc & OB_RECALC_OB)
+                       base->flag |= BA_HAS_RECALC_OB;
+               if(base->object->recalc & OB_RECALC_DATA)
+                       base->flag |= BA_HAS_RECALC_DATA;
+       }
+
+       return total;
+}
+
 static void clear_trans_object_base_flags(TransInfo *t)
 {
        Scene *sce = t->scene;
@@ -4389,7 +4467,7 @@ static void clear_trans_object_base_flags(TransInfo *t)
                if(base->flag & BA_WAS_SEL)
                        base->flag |= SELECT;
 
-               base->flag &= ~(BA_WAS_SEL|BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA|BA_DO_IPO|BA_TRANSFORM_CHILD);
+               base->flag &= ~(BA_WAS_SEL|BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA|BA_DO_IPO|BA_TRANSFORM_CHILD|BA_TRANSFORM_PARENT);
        }
 }
 
@@ -4972,19 +5050,23 @@ static void createTransObject(bContext *C, TransInfo *t)
 {
        TransData *td = NULL;
        TransDataExtension *tx;
-//     IpoKey *ik;
-//     ListBase elems;
+       int propmode = t->flag & T_PROP_EDIT;
 
        set_trans_object_base_flags(C, t);
 
        /* count */
        t->total= CTX_DATA_COUNT(C, selected_objects);
-
+       
        if(!t->total) {
                /* clear here, main transform function escapes too */
                clear_trans_object_base_flags(t);
                return;
        }
+       
+       if (propmode)
+       {
+               t->total += count_proportional_objects(t);
+       }
 
        td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransOb");
        tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransObExtension");
@@ -5015,6 +5097,30 @@ static void createTransObject(bContext *C, TransInfo *t)
                tx++;
        }
        CTX_DATA_END;
+       
+       if (propmode)
+       {
+               Scene *scene = t->scene;
+               View3D *v3d = t->view;
+               Base *base;
+
+               for (base= scene->base.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))
+                       {
+                               td->protectflag= ob->protectflag;
+                               td->ext = tx;
+                               td->rotOrder= ob->rotmode;
+                               
+                               ObjectToTransData(C, t, td, ob);
+                               td->val = NULL;
+                               td++;
+                               tx++;
+                       }
+               }
+       }
 }
 
 /* transcribe given node into TransData2D for Transforming */
@@ -5145,6 +5251,8 @@ void createTransData(bContext *C, TransInfo *t)
                        printf("edit type not implemented!\n");
                }
 
+               t->flag |= T_EDIT|T_POINTS;
+
                if(t->data && t->flag & T_PROP_EDIT) {
                        if (ELEM(t->obedit->type, OB_CURVE, OB_MESH)) {
                                sort_trans_data(t);     // makes selected become first in array
@@ -5158,8 +5266,6 @@ void createTransData(bContext *C, TransInfo *t)
                        }
                }
 
-               t->flag |= T_EDIT|T_POINTS;
-
                /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
                if(t->mode==TFM_BONESIZE) {
                        t->flag &= ~(T_EDIT|T_POINTS);
@@ -5190,22 +5296,27 @@ void createTransData(bContext *C, TransInfo *t)
        else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) 
                && PE_start_edit(PE_get_current(scene, ob))) {
                createTransParticleVerts(C, t);
+               t->flag |= T_POINTS;
 
                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);
                }
-
-               t->flag |= T_POINTS;
        }
        else {
-               t->flag &= ~T_PROP_EDIT; /* no proportional edit in object mode */
+               // t->flag &= ~T_PROP_EDIT; /* no proportional edit in object mode */
                t->options |= CTX_NO_PET;
                
                createTransObject(C, t);
                t->flag |= T_OBJECT;
 
+               if(t->data && t->flag & T_PROP_EDIT) {
+                       // selected objects are already first, no need to presort
+                       set_prop_dist(t, 1);
+                       sort_trans_data_dist(t);
+               }
+
                if (t->ar->regiontype == RGN_TYPE_WINDOW)
                {
                        View3D *v3d = t->view;