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