Merge branch 'blender2.7'
[blender.git] / source / blender / editors / render / render_shading.c
index 99abb8b61c77ab678b56692743f3e7a544f2005c..53fc82e3482f12e8d8a069f4cba47ed367244d5a 100644 (file)
 
 #include "render_intern.h"  // own include
 
+/**
+ * Object list for material operations.
+ * has exception for pinned object.
+ */
+static Object **object_array_for_shading(bContext *C, uint *r_objects_len)
+{
+       ScrArea *sa = CTX_wm_area(C);
+       SpaceButs *sbuts = NULL;
+       View3D *v3d = NULL;
+       if (sa->spacetype == SPACE_BUTS) {
+               sbuts = sa->spacedata.first;
+       }
+       else if (sa->spacetype == SPACE_VIEW3D) {
+               v3d = sa->spacedata.first;
+       }
+
+       Object **objects;
+       if (sbuts && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) {
+               objects = MEM_mallocN(sizeof(*objects), __func__);
+               objects[0] = (Object *)sbuts->pinid;
+               *r_objects_len = 1;
+       }
+       else {
+               ViewLayer *view_layer = CTX_data_view_layer(C);
+               objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_objects_len);
+       }
+       return objects;
+}
+
 /********************** material slot operators *********************/
 
 static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -160,7 +189,7 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
                WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
        }
 
-       DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
        WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
        WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
        WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob);
@@ -185,13 +214,17 @@ void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
 
 static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
 {
-       Object *ob = ED_object_context(C);
        View3D *v3d = CTX_wm_view3d(C);
-
-       if (!ob)
-               return OPERATOR_CANCELLED;
-
-       if (ob && ob->actcol > 0) {
+       bool changed_multi = false;
+
+       uint objects_len = 0;
+       Object **objects = object_array_for_shading(C, &objects_len);
+       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+               Object *ob = objects[ob_index];
+               if (ob->actcol <= 0) {
+                       continue;
+               }
+               bool changed = false;
                if (ob->type == OB_MESH) {
                        BMEditMesh *em = BKE_editmesh_from_object(ob);
                        BMFace *efa;
@@ -199,8 +232,10 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
 
                        if (em) {
                                BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
-                                       if (BM_elem_flag_test(efa, BM_ELEM_SELECT))
+                                       if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+                                               changed = true;
                                                efa->mat_nr = ob->actcol - 1;
+                                       }
                                }
                        }
                }
@@ -211,6 +246,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
                        if (nurbs) {
                                for (nu = nurbs->first; nu; nu = nu->next) {
                                        if (ED_curve_nurb_select_check(v3d, nu)) {
+                                               changed = true;
                                                nu->mat_nr = ob->actcol - 1;
                                        }
                                }
@@ -221,16 +257,22 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
                        int i, selstart, selend;
 
                        if (ef && BKE_vfont_select_get(ob, &selstart, &selend)) {
-                               for (i = selstart; i <= selend; i++)
+                               for (i = selstart; i <= selend; i++) {
+                                       changed = true;
                                        ef->textbufinfo[i].mat_nr = ob->actcol;
+                               }
                        }
                }
-       }
 
-       DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+               if (changed) {
+                       changed_multi = true;
+                       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+                       WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+               }
+       }
+       MEM_freeN(objects);
 
-       return OPERATOR_FINISHED;
+       return (changed_multi) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 }
 
 void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
@@ -250,67 +292,78 @@ void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
 
 static int material_slot_de_select(bContext *C, bool select)
 {
-       Object *ob = ED_object_context(C);
+       bool changed_multi = false;
 
-       if (!ob)
-               return OPERATOR_CANCELLED;
+       uint objects_len = 0;
+       Object **objects = object_array_for_shading(C, &objects_len);
+       for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+               Object *ob = objects[ob_index];
+               bool changed = false;
 
-       if (ob->type == OB_MESH) {
-               BMEditMesh *em = BKE_editmesh_from_object(ob);
+               if (ob->type == OB_MESH) {
+                       BMEditMesh *em = BKE_editmesh_from_object(ob);
 
-               if (em) {
-                       EDBM_deselect_by_material(em, ob->actcol - 1, select);
+                       if (em) {
+                               changed = EDBM_deselect_by_material(em, ob->actcol - 1, select);
+                       }
                }
-       }
-       else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
-               ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
-               Nurb *nu;
-               BPoint *bp;
-               BezTriple *bezt;
-               int a;
-
-               if (nurbs) {
-                       for (nu = nurbs->first; nu; nu = nu->next) {
-                               if (nu->mat_nr == ob->actcol - 1) {
-                                       if (nu->bezt) {
-                                               a = nu->pntsu;
-                                               bezt = nu->bezt;
-                                               while (a--) {
-                                                       if (bezt->hide == 0) {
-                                                               if (select) {
-                                                                       bezt->f1 |= SELECT;
-                                                                       bezt->f2 |= SELECT;
-                                                                       bezt->f3 |= SELECT;
-                                                               }
-                                                               else {
-                                                                       bezt->f1 &= ~SELECT;
-                                                                       bezt->f2 &= ~SELECT;
-                                                                       bezt->f3 &= ~SELECT;
+               else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+                       ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
+                       Nurb *nu;
+                       BPoint *bp;
+                       BezTriple *bezt;
+                       int a;
+
+                       if (nurbs) {
+                               for (nu = nurbs->first; nu; nu = nu->next) {
+                                       if (nu->mat_nr == ob->actcol - 1) {
+                                               if (nu->bezt) {
+                                                       a = nu->pntsu;
+                                                       bezt = nu->bezt;
+                                                       while (a--) {
+                                                               if (bezt->hide == 0) {
+                                                                       changed = true;
+                                                                       if (select) {
+                                                                               bezt->f1 |= SELECT;
+                                                                               bezt->f2 |= SELECT;
+                                                                               bezt->f3 |= SELECT;
+                                                                       }
+                                                                       else {
+                                                                               bezt->f1 &= ~SELECT;
+                                                                               bezt->f2 &= ~SELECT;
+                                                                               bezt->f3 &= ~SELECT;
+                                                                       }
                                                                }
+                                                               bezt++;
                                                        }
-                                                       bezt++;
                                                }
-                                       }
-                                       else if (nu->bp) {
-                                               a = nu->pntsu * nu->pntsv;
-                                               bp = nu->bp;
-                                               while (a--) {
-                                                       if (bp->hide == 0) {
-                                                               if (select) bp->f1 |= SELECT;
-                                                               else bp->f1 &= ~SELECT;
+                                               else if (nu->bp) {
+                                                       a = nu->pntsu * nu->pntsv;
+                                                       bp = nu->bp;
+                                                       while (a--) {
+                                                               if (bp->hide == 0) {
+                                                                       changed = true;
+                                                                       if (select) bp->f1 |= SELECT;
+                                                                       else bp->f1 &= ~SELECT;
+                                                               }
+                                                               bp++;
                                                        }
-                                                       bp++;
                                                }
                                        }
                                }
                        }
                }
+
+               if (changed) {
+                       changed_multi = true;
+                       DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+                       WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+               }
        }
 
-       DEG_id_tag_update(ob->data, DEG_TAG_SELECT_UPDATE);
-       WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+       MEM_freeN(objects);
 
-       return OPERATOR_FINISHED;
+       return (changed_multi) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 }
 
 static int material_slot_select_exec(bContext *C, wmOperator *UNUSED(op))
@@ -369,7 +422,7 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
 
                        if (ob_iter->totcol == ob->totcol) {
                                ob_iter->actcol = ob->actcol;
-                               DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
+                               DEG_id_tag_update(&ob_iter->id, ID_RECALC_GEOMETRY);
                                WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
                        }
                }
@@ -434,7 +487,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
 
        MEM_freeN(slot_remap);
 
-       DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
        WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
        WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
 
@@ -470,29 +523,40 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
        Main *bmain = CTX_data_main(C);
-       Object *ob = CTX_data_active_object(C);
        PointerRNA ptr, idptr;
        PropertyRNA *prop;
 
+       /* hook into UI */
+       UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
+
+       Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL;
+
        /* add or copy material */
        if (ma) {
                ma = BKE_material_copy(bmain, ma);
        }
        else {
-               if ((!ob) || (ob->type != OB_GPENCIL)) {
-                       ma = BKE_material_add(bmain, DATA_("Material"));
+               const char *name = DATA_("Material");
+               if (!(ob != NULL && ob->type == OB_GPENCIL)) {
+                       ma = BKE_material_add(bmain, name);
                }
                else {
-                       ma = BKE_material_add_gpencil(bmain, DATA_("Material"));
+                       ma = BKE_material_add_gpencil(bmain, name);
                }
                ED_node_shader_default(C, &ma->id);
                ma->use_nodes = true;
        }
 
-       /* hook into UI */
-       UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
 
        if (prop) {
+               if (ob != NULL) {
+                       /* Add slot follows user-preferences for creating new slots,
+                        * RNA pointer assignment doesn't, see: T60014. */
+                       if (give_current_material_p(ob, ob->actcol) == NULL) {
+                               BKE_object_material_slot_add(bmain, ob);
+                       }
+               }
+
                /* when creating new ID blocks, use is already 1, but RNA
                 * pointer use also increases user, so this compensates it */
                id_us_min(&ma->id);
@@ -654,6 +718,12 @@ void SCENE_OT_view_layer_add(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
 }
 
+static bool view_layer_remove_poll(bContext *C)
+{
+       Scene *scene = CTX_data_scene(C);
+       return (scene->view_layers.first != scene->view_layers.last);
+}
+
 static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Main *bmain = CTX_data_main(C);
@@ -678,6 +748,7 @@ void SCENE_OT_view_layer_remove(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec = view_layer_remove_exec;
+       ot->poll = view_layer_remove_poll;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -846,7 +917,7 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
 
        EEVEE_lightcache_info_update(&scene->eevee);
 
-       DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+       DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
 
        WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
 
@@ -1705,7 +1776,8 @@ void MATERIAL_OT_copy(wmOperatorType *ot)
        ot->exec = copy_material_exec;
 
        /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL; /* no undo needed since no changes are made to the material */
+       /* no undo needed since no changes are made to the material */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL;
 }
 
 static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1717,6 +1789,7 @@ static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
 
        paste_matcopybuf(CTX_data_main(C), ma);
 
+       DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
        WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
 
        return OPERATOR_FINISHED;
@@ -1837,7 +1910,8 @@ void TEXTURE_OT_slot_copy(wmOperatorType *ot)
        ot->poll = copy_mtex_poll;
 
        /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL; /* no undo needed since no changes are made to the mtex */
+       /* no undo needed since no changes are made to the mtex */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL;
 }
 
 static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))