Blender  V2.93
paint_vertex_color_ops.c
Go to the documentation of this file.
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 
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_deform.h"
33 #include "BKE_mesh.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 
48 {
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;
60  /* NOTE: Original mesh is used for display, so tag it directly here. */
62 }
63 
64 /* -------------------------------------------------------------------- */
68 static bool vertex_color_set(Object *ob, uint paintcol)
69 {
70  Mesh *me;
71  if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
72  return false;
73  }
74 
75  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
76  const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
77 
78  const MPoly *mp = me->mpoly;
79  for (int i = 0; i < me->totpoly; i++, mp++) {
80  MLoopCol *lcol = me->mloopcol + mp->loopstart;
81 
82  if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
83  continue;
84  }
85 
86  int 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  /* remove stale me->mcol, will be added later */
99 
101 
102  return true;
103 }
104 
106 {
108  Object *obact = CTX_data_active_object(C);
110 
111  if (vertex_color_set(obact, paintcol)) {
113  return OPERATOR_FINISHED;
114  }
115  return OPERATOR_CANCELLED;
116 }
117 
119 {
120  /* identifiers */
121  ot->name = "Set Vertex Colors";
122  ot->idname = "PAINT_OT_vertex_color_set";
123  ot->description = "Fill the active vertex color layer with the current paint color";
124 
125  /* api callbacks */
128 
129  /* flags */
131 }
132 
135 /* -------------------------------------------------------------------- */
140 {
141  Mesh *me;
142  const MPoly *mp;
143  int vgroup_active;
144 
145  if (((me = BKE_mesh_from_object(ob)) == NULL || (ED_mesh_color_ensure(me, NULL)) == false)) {
146  return false;
147  }
148 
149  /* TODO: respect selection. */
150  /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway. */
151  mp = me->mpoly;
152  vgroup_active = ob->actdef - 1;
153  for (int i = 0; i < me->totpoly; i++, mp++) {
154  MLoopCol *lcol = &me->mloopcol[mp->loopstart];
155  uint j = 0;
156  do {
157  uint vidx = me->mloop[mp->loopstart + j].v;
158  const float weight = BKE_defvert_find_weight(&me->dvert[vidx], vgroup_active);
159  const uchar grayscale = weight * 255;
160  lcol->r = grayscale;
161  lcol->b = grayscale;
162  lcol->g = grayscale;
163  lcol++;
164  j++;
165  } while (j < mp->totloop);
166  }
167 
169 
170  return true;
171 }
172 
174 {
175  Object *obact = CTX_data_active_object(C);
176  if (vertex_paint_from_weight(obact)) {
178  return OPERATOR_FINISHED;
179  }
180  return OPERATOR_CANCELLED;
181 }
182 
184 {
185  /* identifiers */
186  ot->name = "Vertex Color from Weight";
187  ot->idname = "PAINT_OT_vertex_color_from_weight";
188  ot->description = "Convert active weight into gray scale vertex colors";
189 
190  /* api callback */
193 
194  /* flags */
196 
197  /* TODO: invert, alpha */
198 }
199 
202 /* -------------------------------------------------------------------- */
206 static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
207 {
208  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
209  const MPoly *mp;
210  int(*scol)[4];
211  bool has_shared = false;
212 
213  /* if no mloopcol: do not do */
214  /* if mtexpoly: only the involved faces, otherwise all */
215 
216  if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) {
217  return;
218  }
219 
220  scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
221 
222  int i;
223  for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
224  if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
225  const MLoop *ml = me->mloop + mp->loopstart;
226  MLoopCol *lcol = me->mloopcol + mp->loopstart;
227  for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
228  scol[ml->v][0] += lcol->r;
229  scol[ml->v][1] += lcol->g;
230  scol[ml->v][2] += lcol->b;
231  scol[ml->v][3] += 1;
232  has_shared = 1;
233  }
234  }
235  }
236 
237  if (has_shared) {
238  for (i = 0; i < me->totvert; i++) {
239  if (scol[i][3] != 0) {
240  scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
241  scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
242  scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
243  }
244  }
245 
246  for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
247  if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
248  const MLoop *ml = me->mloop + mp->loopstart;
249  MLoopCol *lcol = me->mloopcol + mp->loopstart;
250  for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
251  if (mlooptag[mp->loopstart + j]) {
252  lcol->r = scol[ml->v][0];
253  lcol->g = scol[ml->v][1];
254  lcol->b = scol[ml->v][2];
255  }
256  }
257  }
258  }
259  }
260 
261  MEM_freeN(scol);
262 }
263 
264 static bool vertex_color_smooth(Object *ob)
265 {
266  Mesh *me;
267  const MPoly *mp;
268  int i, j;
269 
270  bool *mlooptag;
271 
272  if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
273  return false;
274  }
275 
276  const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
277  const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
278 
279  mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
280 
281  /* simply tag loops of selected faces */
282  mp = me->mpoly;
283  for (i = 0; i < me->totpoly; i++, mp++) {
284  const MLoop *ml = me->mloop + mp->loopstart;
285 
286  if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
287  continue;
288  }
289 
290  j = 0;
291  do {
292  if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
293  mlooptag[mp->loopstart + j] = true;
294  }
295  ml++;
296  j++;
297  } while (j < mp->totloop);
298  }
299 
300  /* remove stale me->mcol, will be added later */
302 
303  vertex_color_smooth_looptag(me, mlooptag);
304 
305  MEM_freeN(mlooptag);
306 
308 
309  return true;
310 }
311 
313 {
314  Object *obact = CTX_data_active_object(C);
315  if (vertex_color_smooth(obact)) {
317  return OPERATOR_FINISHED;
318  }
319  return OPERATOR_CANCELLED;
320 }
321 
323 {
324  /* identifiers */
325  ot->name = "Smooth Vertex Colors";
326  ot->idname = "PAINT_OT_vertex_color_smooth";
327  ot->description = "Smooth colors across vertices";
328 
329  /* api callbacks */
332 
333  /* flags */
335 }
336 
339 /* -------------------------------------------------------------------- */
344  /* pre-calculated */
345  float gain;
346  float offset;
347 };
348 
349 static void vpaint_tx_brightness_contrast(const float col[3],
350  const void *user_data,
351  float r_col[3])
352 {
354 
355  for (int i = 0; i < 3; i++) {
356  r_col[i] = data->gain * col[i] + data->offset;
357  }
358 }
359 
361 {
362  Object *obact = CTX_data_active_object(C);
363 
364  float gain, offset;
365  {
366  float brightness = RNA_float_get(op->ptr, "brightness");
367  float contrast = RNA_float_get(op->ptr, "contrast");
368  brightness /= 100.0f;
369  float delta = contrast / 200.0f;
370  /*
371  * The algorithm is by Werner D. Streidt
372  * (http://visca.com/ffactory/archives/5-99/msg00021.html)
373  * Extracted of OpenCV demhist.c
374  */
375  if (contrast > 0) {
376  gain = 1.0f - delta * 2.0f;
377  gain = 1.0f / max_ff(gain, FLT_EPSILON);
378  offset = gain * (brightness - delta);
379  }
380  else {
381  delta *= -1;
382  gain = max_ff(1.0f - delta * 2.0f, 0.0f);
383  offset = gain * brightness + delta;
384  }
385  }
386 
387  const struct VPaintTx_BrightContrastData user_data = {
388  .gain = gain,
389  .offset = offset,
390  };
391 
394  return OPERATOR_FINISHED;
395  }
396  return OPERATOR_CANCELLED;
397 }
398 
400 {
401  PropertyRNA *prop;
402 
403  /* identifiers */
404  ot->name = "Vertex Paint Brightness/Contrast";
405  ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
406  ot->description = "Adjust vertex color brightness/contrast";
407 
408  /* api callbacks */
411 
412  /* flags */
414 
415  /* params */
416  const float min = -100, max = +100;
417  prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
418  prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
419  RNA_def_property_ui_range(prop, min, max, 1, 1);
420 }
421 
423  float hue;
424  float sat;
425  float val;
426 };
427 
428 static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
429 {
430  const struct VPaintTx_HueSatData *data = user_data;
431  float hsv[3];
432  rgb_to_hsv_v(col, hsv);
433 
434  hsv[0] += (data->hue - 0.5f);
435  if (hsv[0] > 1.0f) {
436  hsv[0] -= 1.0f;
437  }
438  else if (hsv[0] < 0.0f) {
439  hsv[0] += 1.0f;
440  }
441  hsv[1] *= data->sat;
442  hsv[2] *= data->val;
443 
444  hsv_to_rgb_v(hsv, r_col);
445 }
446 
448 {
449  Object *obact = CTX_data_active_object(C);
450 
451  const struct VPaintTx_HueSatData user_data = {
452  .hue = RNA_float_get(op->ptr, "h"),
453  .sat = RNA_float_get(op->ptr, "s"),
454  .val = RNA_float_get(op->ptr, "v"),
455  };
456 
459  return OPERATOR_FINISHED;
460  }
461  return OPERATOR_CANCELLED;
462 }
463 
465 {
466  /* identifiers */
467  ot->name = "Vertex Paint Hue Saturation Value";
468  ot->idname = "PAINT_OT_vertex_color_hsv";
469  ot->description = "Adjust vertex color HSV values";
470 
471  /* api callbacks */
474 
475  /* flags */
477 
478  /* params */
479  RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
480  RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
481  RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
482 }
483 
484 static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
485 {
486  for (int i = 0; i < 3; i++) {
487  r_col[i] = 1.0f - col[i];
488  }
489 }
490 
492 {
493  Object *obact = CTX_data_active_object(C);
494 
497  return OPERATOR_FINISHED;
498  }
499  return OPERATOR_CANCELLED;
500 }
501 
503 {
504  /* identifiers */
505  ot->name = "Vertex Paint Invert";
506  ot->idname = "PAINT_OT_vertex_color_invert";
507  ot->description = "Invert RGB values";
508 
509  /* api callbacks */
512 
513  /* flags */
515 }
516 
518  float gain;
519  float offset;
520 };
521 
522 static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
523 {
524  const struct VPaintTx_LevelsData *data = user_data;
525  for (int i = 0; i < 3; i++) {
526  r_col[i] = data->gain * (col[i] + data->offset);
527  }
528 }
529 
531 {
532  Object *obact = CTX_data_active_object(C);
533 
534  const struct VPaintTx_LevelsData user_data = {
535  .gain = RNA_float_get(op->ptr, "gain"),
536  .offset = RNA_float_get(op->ptr, "offset"),
537  };
538 
541  return OPERATOR_FINISHED;
542  }
543  return OPERATOR_CANCELLED;
544 }
545 
547 {
548  /* identifiers */
549  ot->name = "Vertex Paint Levels";
550  ot->idname = "PAINT_OT_vertex_color_levels";
551  ot->description = "Adjust levels of vertex colors";
552 
553  /* api callbacks */
556 
557  /* flags */
559 
560  /* params */
562  ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
564  ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
565 }
566 
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
void BKE_mesh_tessface_clear(struct Mesh *mesh)
Definition: mesh.c:1567
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.c:1271
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
Definition: mesh_runtime.c:251
@ BKE_MESH_BATCH_DIRTY_ALL
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE float max_ff(float a, float b)
MINLINE int divide_round_i(int a, int b)
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition: math_color.c:68
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Definition: math_color.c:254
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
@ ME_FACE_SEL
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_VERTEX_PAINT
Object is a sort of wrapper for general info.
@ OB_MESH
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
Definition: mesh_data.c:433
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
#define ND_DRAW
Definition: WM_types.h:362
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define NC_OBJECT
Definition: WM_types.h:280
#define SELECT
Scene scene
void * user_data
uint col
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
bool vertex_paint_mode_poll(struct bContext *C)
Definition: paint_vertex.c:205
unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary)
Definition: paint_vertex.c:273
bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data)
void PAINT_OT_vertex_color_set(wmOperatorType *ot)
static bool vertex_color_smooth(Object *ob)
void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
static bool vertex_weight_paint_mode_poll(bContext *C)
void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
static int vertex_color_levels_exec(bContext *C, wmOperator *op)
static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
static void tag_object_after_update(Object *object)
static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3])
void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
static bool vertex_paint_from_weight(Object *ob)
static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
static bool vertex_color_set(Object *ob, uint paintcol)
static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
Definition: rna_define.c:1706
#define min(a, b)
Definition: sort.c:51
unsigned char b
unsigned char r
unsigned char g
unsigned int v
struct MVert * mvert
struct MLoopCol * mloopcol
struct MDeformVert * dvert
char editflag
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
unsigned short actdef
struct ToolSettings * toolsettings
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct PointerRNA * ptr
float max
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156