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