Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / sculpt_paint / paint_vertex_color_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file blender/editors/sculpt_paint/paint_vertex_color_ops.c
22  *  \ingroup edsculpt
23  */
24
25 #include "MEM_guardedalloc.h"
26
27 #include "DNA_mesh_types.h"
28 #include "DNA_meshdata_types.h"
29 #include "DNA_object_types.h"
30 #include "DNA_scene_types.h"
31
32 #include "BLI_math_base.h"
33 #include "BLI_math_color.h"
34
35 #include "BKE_context.h"
36 #include "BKE_mesh.h"
37 #include "BKE_deform.h"
38
39 #include "DEG_depsgraph.h"
40
41 #include "RNA_access.h"
42 #include "RNA_define.h"
43
44 #include "WM_api.h"
45 #include "WM_types.h"
46
47 #include "ED_mesh.h"
48
49 #include "paint_intern.h"  /* own include */
50
51
52 static int vertex_weight_paint_mode_poll(bContext *C)
53 {
54         Object *ob = CTX_data_active_object(C);
55         Mesh *me = BKE_mesh_from_object(ob);
56         return (ob && (ob->mode == OB_MODE_VERTEX_PAINT || ob->mode == OB_MODE_WEIGHT_PAINT)) &&
57                (me && me->totpoly && me->dvert);
58 }
59
60 /* -------------------------------------------------------------------- */
61 /** \name Set Vertex Colors Operator
62  * \{ */
63
64 static bool vertex_color_set(Object *ob, uint paintcol)
65 {
66         Mesh *me;
67         const MPoly *mp;
68         int i, j;
69
70         if (((me = BKE_mesh_from_object(ob)) == NULL) ||
71             (ED_mesh_color_ensure(me, NULL) == false))
72         {
73                 return false;
74         }
75
76         const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
77         const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
78
79         mp = me->mpoly;
80         for (i = 0; i < me->totpoly; i++, mp++) {
81                 MLoopCol *lcol = me->mloopcol + mp->loopstart;
82
83                 if (use_face_sel && !(mp->flag & ME_FACE_SEL))
84                         continue;
85
86                 j = 0;
87                 do {
88                         uint vidx = me->mloop[mp->loopstart + j].v;
89                         if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
90                                 *(int *)lcol = paintcol;
91                         }
92                         lcol++;
93                         j++;
94                 } while (j < mp->totloop);
95
96         }
97
98         /* remove stale me->mcol, will be added later */
99         BKE_mesh_tessface_clear(me);
100
101         DEG_id_tag_update(&me->id, 0);
102
103         return true;
104 }
105
106 static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
107 {
108         Scene *scene = CTX_data_scene(C);
109         Object *obact = CTX_data_active_object(C);
110         unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint);
111
112         if (vertex_color_set(obact, paintcol)) {
113                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
114                 return OPERATOR_FINISHED;
115         }
116         else {
117                 return OPERATOR_CANCELLED;
118         }
119 }
120
121 void PAINT_OT_vertex_color_set(wmOperatorType *ot)
122 {
123         /* identifiers */
124         ot->name = "Set Vertex Colors";
125         ot->idname = "PAINT_OT_vertex_color_set";
126         ot->description = "Fill the active vertex color layer with the current paint color";
127
128         /* api callbacks */
129         ot->exec = vertex_color_set_exec;
130         ot->poll = vertex_paint_mode_poll;
131
132         /* flags */
133         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
134 }
135
136 /** \} */
137
138 /* -------------------------------------------------------------------- */
139 /** \name Vertex Color from Weight Operator
140  * \{ */
141
142 static bool vertex_paint_from_weight(Object *ob)
143 {
144         Mesh *me;
145         const MPoly *mp;
146         int vgroup_active;
147
148         if (((me = BKE_mesh_from_object(ob)) == NULL ||
149             (ED_mesh_color_ensure(me, NULL)) == false))
150         {
151                 return false;
152         }
153
154         /* TODO: respect selection. */
155         mp = me->mpoly;
156         vgroup_active = ob->actdef - 1;
157         for (int i = 0; i < me->totpoly; i++, mp++) {
158                 MLoopCol *lcol = &me->mloopcol[mp->loopstart];
159                 uint j = 0;
160                 do {
161                         uint vidx = me->mloop[mp->loopstart + j].v;
162                         const float weight = defvert_find_weight(&me->dvert[vidx], vgroup_active);
163                         const uchar grayscale = weight * 255;
164                         lcol->r = grayscale;
165                         lcol->b = grayscale;
166                         lcol->g = grayscale;
167                         lcol++;
168                         j++;
169                 } while (j < mp->totloop);
170         }
171
172         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
173
174         return true;
175 }
176
177 static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
178 {
179         Object *obact = CTX_data_active_object(C);
180         if (vertex_paint_from_weight(obact)) {
181                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
182                 return OPERATOR_FINISHED;
183         }
184         else {
185                 return OPERATOR_CANCELLED;
186         }
187 }
188
189 void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
190 {
191         /* identifiers */
192         ot->name = "Vertex Color from Weight";
193         ot->idname = "PAINT_OT_vertex_color_from_weight";
194         ot->description = "Convert active weight into gray scale vertex colors";
195
196         /* api callback */
197         ot->exec = vertex_paint_from_weight_exec;
198         ot->poll = vertex_weight_paint_mode_poll;
199
200         /* flags */
201         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
202
203         /* TODO: invert, alpha */
204 }
205
206 /** \} */
207
208 /* -------------------------------------------------------------------- */
209 /** \name Smooth Vertex Colors Operator
210  * \{ */
211
212 static void vertex_color_smooth_looptag(Mesh *me, bool *mlooptag)
213 {
214         const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
215         const MPoly *mp;
216         int (*scol)[4];
217         int i, j;
218         bool has_shared = false;
219
220         /* if no mloopcol: do not do */
221         /* if mtexpoly: only the involved faces, otherwise all */
222
223         if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return;
224
225         scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
226
227         for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
228                 if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
229                         const MLoop *ml = me->mloop + mp->loopstart;
230                         MLoopCol *lcol = me->mloopcol + mp->loopstart;
231                         for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
232                                 scol[ml->v][0] += lcol->r;
233                                 scol[ml->v][1] += lcol->g;
234                                 scol[ml->v][2] += lcol->b;
235                                 scol[ml->v][3] += 1;
236                                 has_shared = 1;
237                         }
238                 }
239         }
240
241         if (has_shared) {
242                 for (i = 0; i < me->totvert; i++) {
243                         if (scol[i][3] != 0) {
244                                 scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
245                                 scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
246                                 scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
247                         }
248                 }
249
250                 for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
251                         if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
252                                 const MLoop *ml = me->mloop + mp->loopstart;
253                                 MLoopCol *lcol = me->mloopcol + mp->loopstart;
254                                 for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
255                                         if (mlooptag[mp->loopstart + j]) {
256                                                 lcol->r = scol[ml->v][0];
257                                                 lcol->g = scol[ml->v][1];
258                                                 lcol->b = scol[ml->v][2];
259                                         }
260                                 }
261                         }
262                 }
263         }
264
265         MEM_freeN(scol);
266 }
267
268 static bool vertex_color_smooth(Object *ob)
269 {
270         Mesh *me;
271         const MPoly *mp;
272
273         int i, j;
274
275         bool *mlooptag;
276
277         if (((me = BKE_mesh_from_object(ob)) == NULL) ||
278             (ED_mesh_color_ensure(me, NULL) == false))
279         {
280                 return false;
281         }
282
283         const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
284
285         mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
286
287         /* simply tag loops of selected faces */
288         mp = me->mpoly;
289         for (i = 0; i < me->totpoly; i++, mp++) {
290                 const MLoop *ml = me->mloop + mp->loopstart;
291                 int ml_index = mp->loopstart;
292
293                 if (use_face_sel && !(mp->flag & ME_FACE_SEL))
294                         continue;
295
296                 for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
297                         mlooptag[ml_index] = true;
298                 }
299         }
300
301         /* remove stale me->mcol, will be added later */
302         BKE_mesh_tessface_clear(me);
303
304         vertex_color_smooth_looptag(me, mlooptag);
305
306         MEM_freeN(mlooptag);
307
308         DEG_id_tag_update(&me->id, 0);
309
310         return true;
311 }
312
313
314 static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
315 {
316         Object *obact = CTX_data_active_object(C);
317         if (vertex_color_smooth(obact)) {
318                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
319                 return OPERATOR_FINISHED;
320         }
321         else {
322                 return OPERATOR_CANCELLED;
323         }
324 }
325
326 void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
327 {
328         /* identifiers */
329         ot->name = "Smooth Vertex Colors";
330         ot->idname = "PAINT_OT_vertex_color_smooth";
331         ot->description = "Smooth colors across vertices";
332
333         /* api callbacks */
334         ot->exec = vertex_color_smooth_exec;
335         ot->poll = vertex_paint_mode_poll;
336
337         /* flags */
338         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
339 }
340
341 /** \} */
342
343 /* -------------------------------------------------------------------- */
344 /** \name Vertex Color Transformation Operators
345  * \{ */
346
347 struct VPaintTx_BrightContrastData {
348         /* pre-calculated */
349         float gain;
350         float offset;
351 };
352
353 static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3])
354 {
355         const struct VPaintTx_BrightContrastData *data = user_data;
356
357         for (int i = 0; i < 3; i++) {
358                 r_col[i] = data->gain * col[i] + data->offset;
359         }
360 }
361
362 static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
363 {
364         Object *obact = CTX_data_active_object(C);
365
366         float gain, offset;
367         {
368                 float brightness = RNA_float_get(op->ptr, "brightness");
369                 float contrast = RNA_float_get(op->ptr, "contrast");
370                 brightness /= 100.0f;
371                 float delta = contrast / 200.0f;
372                 gain = 1.0f - delta * 2.0f;
373                 /*
374                  * The algorithm is by Werner D. Streidt
375                  * (http://visca.com/ffactory/archives/5-99/msg00021.html)
376                  * Extracted of OpenCV demhist.c
377                  */
378                 if (contrast > 0) {
379                         gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
380                         offset = gain * (brightness - delta);
381                 }
382                 else {
383                         delta *= -1;
384                         offset = gain * (brightness + delta);
385                 }
386         }
387
388         const struct VPaintTx_BrightContrastData user_data = {
389                 .gain = gain,
390                 .offset = offset,
391         };
392
393         if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
394                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
395                 return OPERATOR_FINISHED;
396         }
397         else {
398                 return OPERATOR_CANCELLED;
399         }
400 }
401
402 void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
403 {
404         PropertyRNA *prop;
405
406         /* identifiers */
407         ot->name = "Vertex Paint Bright/Contrast";
408         ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
409         ot->description = "Adjust vertex color brightness/contrast";
410
411         /* api callbacks */
412         ot->exec = vertex_color_brightness_contrast_exec;
413         ot->poll = vertex_paint_mode_poll;
414
415         /* flags */
416         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
417
418         /* params */
419         const float min = -100, max = +100;
420         prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
421         prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
422         RNA_def_property_ui_range(prop, min, max, 1, 1);
423 }
424
425 struct VPaintTx_HueSatData {
426         float hue;
427         float sat;
428         float val;
429 };
430
431 static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
432 {
433         const struct VPaintTx_HueSatData *data = user_data;
434         float hsv[3];
435         rgb_to_hsv_v(col, hsv);
436
437         hsv[0] += (data->hue - 0.5f);
438         if (hsv[0] > 1.0f) {
439                 hsv[0] -= 1.0f;
440         }
441         else if (hsv[0] < 0.0f) {
442                 hsv[0] += 1.0f;
443         }
444         hsv[1] *= data->sat;
445         hsv[2] *= data->val;
446
447         hsv_to_rgb_v(hsv, r_col);
448 }
449
450 static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
451 {
452         Object *obact = CTX_data_active_object(C);
453
454         const struct VPaintTx_HueSatData user_data = {
455                 .hue = RNA_float_get(op->ptr, "h"),
456                 .sat = RNA_float_get(op->ptr, "s"),
457                 .val = RNA_float_get(op->ptr, "v"),
458         };
459
460         if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
461                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
462                 return OPERATOR_FINISHED;
463         }
464         else {
465                 return OPERATOR_CANCELLED;
466         }
467 }
468
469 void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
470 {
471         /* identifiers */
472         ot->name = "Vertex Paint Hue Saturation Value";
473         ot->idname = "PAINT_OT_vertex_color_hsv";
474         ot->description = "Adjust vertex color HSV values";
475
476         /* api callbacks */
477         ot->exec = vertex_color_hsv_exec;
478         ot->poll = vertex_paint_mode_poll;
479
480         /* flags */
481         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
482
483         /* params */
484         RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
485         RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
486         RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
487 }
488
489 static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
490 {
491         for (int i = 0; i < 3; i++) {
492                 r_col[i] = 1.0f - col[i];
493         }
494 }
495
496 static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
497 {
498         Object *obact = CTX_data_active_object(C);
499
500         if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
501                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
502                 return OPERATOR_FINISHED;
503         }
504         else {
505                 return OPERATOR_CANCELLED;
506         }
507 }
508
509 void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
510 {
511         /* identifiers */
512         ot->name = "Vertex Paint Invert";
513         ot->idname = "PAINT_OT_vertex_color_invert";
514         ot->description = "Invert RGB values";
515
516         /* api callbacks */
517         ot->exec = vertex_color_invert_exec;
518         ot->poll = vertex_paint_mode_poll;
519
520         /* flags */
521         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
522 }
523
524
525 struct VPaintTx_LevelsData {
526         float gain;
527         float offset;
528 };
529
530 static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
531 {
532         const struct VPaintTx_LevelsData *data = user_data;
533         for (int i = 0; i < 3; i++) {
534                 r_col[i] = data->gain * (col[i] + data->offset);
535         }
536 }
537
538 static int vertex_color_levels_exec(bContext *C, wmOperator *op)
539 {
540         Object *obact = CTX_data_active_object(C);
541
542         const struct VPaintTx_LevelsData user_data = {
543                 .gain = RNA_float_get(op->ptr, "gain"),
544                 .offset = RNA_float_get(op->ptr, "offset"),
545         };
546
547         if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
548                 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
549                 return OPERATOR_FINISHED;
550         }
551         else {
552                 return OPERATOR_CANCELLED;
553         }
554 }
555
556 void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
557 {
558         /* identifiers */
559         ot->name = "Vertex Paint Levels";
560         ot->idname = "PAINT_OT_vertex_color_levels";
561         ot->description = "Adjust levels of vertex colors";
562
563         /* api callbacks */
564         ot->exec = vertex_color_levels_exec;
565         ot->poll = vertex_paint_mode_poll;
566
567         /* flags */
568         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
569
570         /* params */
571         RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
572         RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
573 }
574
575 /** \} */