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