Cleanup: extra semicolon, comma warnings
[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   int i, j;
276
277   bool *mlooptag;
278
279   if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
280     return false;
281   }
282
283   const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
284   const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_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
293     if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
294       continue;
295     }
296
297     j = 0;
298     do {
299       if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
300         mlooptag[mp->loopstart + j] = true;
301       }
302       ml++;
303       j++;
304     } while (j < mp->totloop);
305   }
306
307   /* remove stale me->mcol, will be added later */
308   BKE_mesh_tessface_clear(me);
309
310   vertex_color_smooth_looptag(me, mlooptag);
311
312   MEM_freeN(mlooptag);
313
314   tag_object_after_update(ob);
315
316   return true;
317 }
318
319 static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
320 {
321   Object *obact = CTX_data_active_object(C);
322   if (vertex_color_smooth(obact)) {
323     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
324     return OPERATOR_FINISHED;
325   }
326   else {
327     return OPERATOR_CANCELLED;
328   }
329 }
330
331 void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
332 {
333   /* identifiers */
334   ot->name = "Smooth Vertex Colors";
335   ot->idname = "PAINT_OT_vertex_color_smooth";
336   ot->description = "Smooth colors across vertices";
337
338   /* api callbacks */
339   ot->exec = vertex_color_smooth_exec;
340   ot->poll = vertex_paint_mode_poll;
341
342   /* flags */
343   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
344 }
345
346 /** \} */
347
348 /* -------------------------------------------------------------------- */
349 /** \name Vertex Color Transformation Operators
350  * \{ */
351
352 struct VPaintTx_BrightContrastData {
353   /* pre-calculated */
354   float gain;
355   float offset;
356 };
357
358 static void vpaint_tx_brightness_contrast(const float col[3],
359                                           const void *user_data,
360                                           float r_col[3])
361 {
362   const struct VPaintTx_BrightContrastData *data = user_data;
363
364   for (int i = 0; i < 3; i++) {
365     r_col[i] = data->gain * col[i] + data->offset;
366   }
367 }
368
369 static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
370 {
371   Object *obact = CTX_data_active_object(C);
372
373   float gain, offset;
374   {
375     float brightness = RNA_float_get(op->ptr, "brightness");
376     float contrast = RNA_float_get(op->ptr, "contrast");
377     brightness /= 100.0f;
378     float delta = contrast / 200.0f;
379     /*
380      * The algorithm is by Werner D. Streidt
381      * (http://visca.com/ffactory/archives/5-99/msg00021.html)
382      * Extracted of OpenCV demhist.c
383      */
384     if (contrast > 0) {
385       gain = 1.0f - delta * 2.0f;
386       gain = 1.0f / max_ff(gain, FLT_EPSILON);
387       offset = gain * (brightness - delta);
388     }
389     else {
390       delta *= -1;
391       gain = max_ff(1.0f - delta * 2.0f, 0.0f);
392       offset = gain * brightness + delta;
393     }
394   }
395
396   const struct VPaintTx_BrightContrastData user_data = {
397       .gain = gain,
398       .offset = offset,
399   };
400
401   if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
402     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
403     return OPERATOR_FINISHED;
404   }
405   else {
406     return OPERATOR_CANCELLED;
407   }
408 }
409
410 void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
411 {
412   PropertyRNA *prop;
413
414   /* identifiers */
415   ot->name = "Vertex Paint Bright/Contrast";
416   ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
417   ot->description = "Adjust vertex color brightness/contrast";
418
419   /* api callbacks */
420   ot->exec = vertex_color_brightness_contrast_exec;
421   ot->poll = vertex_paint_mode_poll;
422
423   /* flags */
424   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
425
426   /* params */
427   const float min = -100, max = +100;
428   prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
429   prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
430   RNA_def_property_ui_range(prop, min, max, 1, 1);
431 }
432
433 struct VPaintTx_HueSatData {
434   float hue;
435   float sat;
436   float val;
437 };
438
439 static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
440 {
441   const struct VPaintTx_HueSatData *data = user_data;
442   float hsv[3];
443   rgb_to_hsv_v(col, hsv);
444
445   hsv[0] += (data->hue - 0.5f);
446   if (hsv[0] > 1.0f) {
447     hsv[0] -= 1.0f;
448   }
449   else if (hsv[0] < 0.0f) {
450     hsv[0] += 1.0f;
451   }
452   hsv[1] *= data->sat;
453   hsv[2] *= data->val;
454
455   hsv_to_rgb_v(hsv, r_col);
456 }
457
458 static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
459 {
460   Object *obact = CTX_data_active_object(C);
461
462   const struct VPaintTx_HueSatData user_data = {
463       .hue = RNA_float_get(op->ptr, "h"),
464       .sat = RNA_float_get(op->ptr, "s"),
465       .val = RNA_float_get(op->ptr, "v"),
466   };
467
468   if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
469     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
470     return OPERATOR_FINISHED;
471   }
472   else {
473     return OPERATOR_CANCELLED;
474   }
475 }
476
477 void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
478 {
479   /* identifiers */
480   ot->name = "Vertex Paint Hue Saturation Value";
481   ot->idname = "PAINT_OT_vertex_color_hsv";
482   ot->description = "Adjust vertex color HSV values";
483
484   /* api callbacks */
485   ot->exec = vertex_color_hsv_exec;
486   ot->poll = vertex_paint_mode_poll;
487
488   /* flags */
489   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
490
491   /* params */
492   RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
493   RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
494   RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
495 }
496
497 static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
498 {
499   for (int i = 0; i < 3; i++) {
500     r_col[i] = 1.0f - col[i];
501   }
502 }
503
504 static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
505 {
506   Object *obact = CTX_data_active_object(C);
507
508   if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
509     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
510     return OPERATOR_FINISHED;
511   }
512   else {
513     return OPERATOR_CANCELLED;
514   }
515 }
516
517 void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
518 {
519   /* identifiers */
520   ot->name = "Vertex Paint Invert";
521   ot->idname = "PAINT_OT_vertex_color_invert";
522   ot->description = "Invert RGB values";
523
524   /* api callbacks */
525   ot->exec = vertex_color_invert_exec;
526   ot->poll = vertex_paint_mode_poll;
527
528   /* flags */
529   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
530 }
531
532 struct VPaintTx_LevelsData {
533   float gain;
534   float offset;
535 };
536
537 static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
538 {
539   const struct VPaintTx_LevelsData *data = user_data;
540   for (int i = 0; i < 3; i++) {
541     r_col[i] = data->gain * (col[i] + data->offset);
542   }
543 }
544
545 static int vertex_color_levels_exec(bContext *C, wmOperator *op)
546 {
547   Object *obact = CTX_data_active_object(C);
548
549   const struct VPaintTx_LevelsData user_data = {
550       .gain = RNA_float_get(op->ptr, "gain"),
551       .offset = RNA_float_get(op->ptr, "offset"),
552   };
553
554   if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
555     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
556     return OPERATOR_FINISHED;
557   }
558   else {
559     return OPERATOR_CANCELLED;
560   }
561 }
562
563 void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
564 {
565   /* identifiers */
566   ot->name = "Vertex Paint Levels";
567   ot->idname = "PAINT_OT_vertex_color_levels";
568   ot->description = "Adjust levels of vertex colors";
569
570   /* api callbacks */
571   ot->exec = vertex_color_levels_exec;
572   ot->poll = vertex_paint_mode_poll;
573
574   /* flags */
575   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
576
577   /* params */
578   RNA_def_float(
579       ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
580   RNA_def_float(
581       ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
582 }
583
584 /** \} */