Weight Paint: 'Sample' now supports multi-paint
authorAlexander Gavrilov <angavrilov@gmail.com>
Tue, 19 Jan 2016 15:57:52 +0000 (18:57 +0300)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 20 Jan 2016 20:11:56 +0000 (07:11 +1100)
Since the coloring uses sum or average of the weights of all selected
groups, the weight pick tool should also use that instead of reading
the weight of the single active group that you can't see.

source/blender/blenkernel/BKE_deform.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/deform.c
source/blender/editors/sculpt_paint/paint_vertex.c

index a45893b00fa9a8f3f29aa3801abdf8a76453446a..e716a7bc8fe8a08d8d294b94f073d7edeea964fd 100644 (file)
@@ -68,6 +68,10 @@ void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *s
 float  defvert_find_weight(const struct MDeformVert *dvert, const int defgroup);
 float  defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup);
 
+float BKE_defvert_multipaint_collective_weight(
+        const struct MDeformVert *dv, int defbase_tot,
+        const bool *defbase_sel, int defbase_tot_sel, bool do_autonormalize);
+
 void defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src);
 void defvert_copy_subset(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
                          const bool *vgroup_subset, const int vgroup_tot);
index 1577a818180bdbb41a7048762c84dd830ebdc62f..dc7ef3055ee7321e96c3d984b814766a135c4e34 100644 (file)
@@ -1373,30 +1373,13 @@ static void calc_weightpaint_vert_color(
 
        if ((defbase_sel_tot > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
                /* Multi-Paint feature */
-               bool was_a_nonzero = false;
-               unsigned int i;
-
-               const MDeformWeight *dw = dv->dw;
-               for (i = dv->totweight; i != 0; i--, dw++) {
-                       /* in multipaint, get the average if auto normalize is inactive
-                        * get the sum if it is active */
-                       if (dw->def_nr < defbase_tot) {
-                               if (defbase_sel[dw->def_nr]) {
-                                       if (dw->weight) {
-                                               input += dw->weight;
-                                               was_a_nonzero = true;
-                                       }
-                               }
-                       }
-               }
+               input = BKE_defvert_multipaint_collective_weight(
+                       dv, defbase_tot, defbase_sel, defbase_sel_tot, (draw_flag & CALC_WP_AUTO_NORMALIZE) != 0);
 
                /* make it black if the selected groups have no weight on a vertex */
-               if (was_a_nonzero == false) {
+               if (input == 0.0f) {
                        show_alert_color = true;
                }
-               else if ((draw_flag & CALC_WP_AUTO_NORMALIZE) == false) {
-                       input /= defbase_sel_tot; /* get the average */
-               }
        }
        else {
                /* default, non tricky behavior */
index b09a0e92edb501941b0d8b545fd48cf08a64102a..135bf3e02ac9343c4dedeaa5da90cb5b1d821c14 100644 (file)
@@ -919,6 +919,40 @@ bool defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_
        return true;
 }
 
+
+/**
+ * \return The representative weight of a multipaint group, used for
+ * viewport colors and actual painting.
+ *
+ * Result equal to sum of weights with auto normalize, and average otherwise.
+ * Value is not clamped, since painting relies on multiplication being always
+ * commutative with the collective weight function.
+ */
+float BKE_defvert_multipaint_collective_weight(
+        const struct MDeformVert *dv, int defbase_tot,
+        const bool *defbase_sel, int defbase_tot_sel, bool do_autonormalize)
+{
+       int i;
+       float total = 0.0f;
+       const MDeformWeight *dw = dv->dw;
+
+       for (i = dv->totweight; i != 0; i--, dw++) {
+               /* in multipaint, get the average if auto normalize is inactive
+                * get the sum if it is active */
+               if (dw->def_nr < defbase_tot) {
+                       if (defbase_sel[dw->def_nr]) {
+                               total += dw->weight;
+                       }
+               }
+       }
+
+       if (do_autonormalize == false) {
+               total /= defbase_tot_sel;
+       }
+
+       return total;
+}
+
 /* -------------------------------------------------------------------- */
 /* Defvert Array functions */
 
index 140c86a206aac08659bd474a628e45c9c10df87a..572d19dc55cae49333314c1b74964671e2b7d854 100644 (file)
@@ -1014,6 +1014,24 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
                        Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
                        const int vgroup_active = vc.obact->actdef - 1;
                        float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
+
+                       /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */
+                       if (ts->multipaint) {
+                               int defbase_tot_sel;
+                               const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+                               bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel);
+
+                               if (defbase_tot_sel > 1) {
+                                       vgroup_weight = BKE_defvert_multipaint_collective_weight(
+                                               &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize);
+
+                                       /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */
+                                       CLAMP(vgroup_weight, 0.0f, 1.0f);
+                               }
+
+                               MEM_freeN(defbase_sel);
+                       }
+
                        BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
                        changed = true;
                }