Blender  V3.3
paint_vertex_color_ops.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MEM_guardedalloc.h"
8 
9 #include "DNA_mesh_types.h"
10 #include "DNA_meshdata_types.h"
11 #include "DNA_object_types.h"
12 #include "DNA_scene_types.h"
13 
14 #include "BLI_array.hh"
15 #include "BLI_index_mask_ops.hh"
16 #include "BLI_math_base.h"
17 #include "BLI_math_color.h"
18 #include "BLI_vector.hh"
19 
20 #include "BKE_attribute_math.hh"
21 #include "BKE_context.h"
22 #include "BKE_deform.h"
23 #include "BKE_geometry_set.hh"
24 #include "BKE_mesh.h"
25 
26 #include "DEG_depsgraph.h"
27 
28 #include "RNA_access.h"
29 #include "RNA_define.h"
30 
31 #include "WM_api.h"
32 #include "WM_types.h"
33 
34 #include "ED_mesh.h"
35 
36 #include "paint_intern.h" /* own include */
37 
38 using blender::Array;
41 using blender::IndexMask;
42 using blender::Vector;
43 
44 /* -------------------------------------------------------------------- */
49 {
51  Mesh *me = BKE_mesh_from_object(ob);
52  return (ob && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) &&
53  (me && me->totpoly && me->dvert);
54 }
55 
56 static void tag_object_after_update(Object *object)
57 {
58  BLI_assert(object->type == OB_MESH);
59  Mesh *mesh = static_cast<Mesh *>(object->data);
61  /* NOTE: Original mesh is used for display, so tag it directly here. */
63 }
64 
67 /* -------------------------------------------------------------------- */
72 {
73  using namespace blender;
74 
75  Mesh *me;
76  if (((me = BKE_mesh_from_object(ob)) == nullptr ||
77  (ED_mesh_color_ensure(me, nullptr)) == false)) {
78  return false;
79  }
80 
81  const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
82  if (active_color_layer == nullptr) {
84  return false;
85  }
86 
87  const int active_vertex_group_index = me->vertex_group_active_index - 1;
88  const bDeformGroup *deform_group = static_cast<const bDeformGroup *>(
89  BLI_findlink(&me->vertex_group_names, active_vertex_group_index));
90  if (deform_group == nullptr) {
92  return false;
93  }
94 
96 
97  bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
98  if (!color_attribute) {
100  return false;
101  }
102 
103  /* Retrieve the vertex group with the domain and type of the existing color
104  * attribute, in order to let the attribute API handle both conversions. */
105  const GVArray vertex_group = attributes.lookup(
106  deform_group->name,
108  bke::cpp_type_to_custom_data_type(color_attribute.varray.type()));
109  if (!vertex_group) {
111  return false;
112  }
113 
114  GVArraySpan interpolated{
115  attributes.adapt_domain(vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)};
116 
117  color_attribute.varray.set_all(interpolated.data());
118  color_attribute.finish();
120 
121  return true;
122 }
123 
125 {
126  Object *obact = CTX_data_active_object(C);
127  if (vertex_paint_from_weight(obact)) {
129  return OPERATOR_FINISHED;
130  }
131  return OPERATOR_CANCELLED;
132 }
133 
135 {
136  /* identifiers */
137  ot->name = "Vertex Color from Weight";
138  ot->idname = "PAINT_OT_vertex_color_from_weight";
139  ot->description = "Convert active weight into gray scale vertex colors";
140 
141  /* api callback */
144 
145  /* flags */
147 
148  /* TODO: invert, alpha */
149 }
150 
153 /* -------------------------------------------------------------------- */
158  const eAttrDomain domain,
160 {
161  using namespace blender;
164 
166 
168  const VArray<bool> selection = attributes.adapt_domain(
170  [&](const int i) { return faces[i].flag & ME_FACE_SEL; }),
172  domain);
173 
175  IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
176  }
178  const VArray<bool> selection = attributes.adapt_domain(
179  VArray<bool>::ForFunc(verts.size(), [&](const int i) { return verts[i].flag & SELECT; }),
181  domain);
182 
184  IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
185  }
186  return IndexMask(attributes.domain_size(domain));
187 }
188 
190 {
191  using namespace blender;
192 
193  const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
194  if (active_color_layer == nullptr) {
196  return;
197  }
198 
200 
201  if (attributes.lookup_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) {
202  return;
203  }
204 
205  GVArray color_attribute_point = attributes.lookup(active_color_layer->name, ATTR_DOMAIN_POINT);
206 
207  GVArray color_attribute_corner = attributes.adapt_domain(
208  color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER);
209 
210  color_attribute_corner.materialize(selection, active_color_layer->data);
211 }
212 
213 static bool vertex_color_smooth(Object *ob)
214 {
215  Mesh *me;
216  if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
217  (ED_mesh_color_ensure(me, nullptr) == false)) {
218  return false;
219  }
220 
222  const IndexMask selection = get_selected_indices(*me, ATTR_DOMAIN_CORNER, indices);
223 
224  face_corner_color_equalize_vertices(*me, selection);
225 
227 
228  return true;
229 }
230 
232 {
233  Object *obact = CTX_data_active_object(C);
234  if (vertex_color_smooth(obact)) {
236  return OPERATOR_FINISHED;
237  }
238  return OPERATOR_CANCELLED;
239 }
240 
242 {
243  /* identifiers */
244  ot->name = "Smooth Vertex Colors";
245  ot->idname = "PAINT_OT_vertex_color_smooth";
246  ot->description = "Smooth colors across vertices";
247 
248  /* api callbacks */
251 
252  /* flags */
254 }
255 
258 /* -------------------------------------------------------------------- */
262 template<typename TransformFn>
263 static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
264 {
265  using namespace blender;
266 
267  const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
268  if (active_color_layer == nullptr) {
270  return false;
271  }
272 
274 
275  bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
276  if (!color_attribute) {
278  return false;
279  }
280 
282  const IndexMask selection = get_selected_indices(mesh, color_attribute.domain, indices);
283 
284  attribute_math::convert_to_static_type(color_attribute.varray.type(), [&](auto dummy) {
285  using T = decltype(dummy);
286  threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
287  for ([[maybe_unused]] const int i : selection.slice(range)) {
288  if constexpr (std::is_same_v<T, ColorGeometry4f>) {
289  ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4f>(i);
290  transform_fn(color);
291  color_attribute.varray.set_by_copy(i, &color);
292  }
293  else if constexpr (std::is_same_v<T, ColorGeometry4b>) {
294  ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4b>(i).decode();
295  transform_fn(color);
296  ColorGeometry4b color_encoded = color.encode();
297  color_attribute.varray.set_by_copy(i, &color_encoded);
298  }
299  }
300  });
301  });
302 
303  color_attribute.finish();
304 
306 
307  return true;
308 }
309 
311 {
312  Object *obact = CTX_data_active_object(C);
313 
314  float gain, offset;
315  {
316  float brightness = RNA_float_get(op->ptr, "brightness");
317  float contrast = RNA_float_get(op->ptr, "contrast");
318  brightness /= 100.0f;
319  float delta = contrast / 200.0f;
320  /*
321  * The algorithm is by Werner D. Streidt
322  * (http://visca.com/ffactory/archives/5-99/msg00021.html)
323  * Extracted of OpenCV demhist.c
324  */
325  if (contrast > 0) {
326  gain = 1.0f - delta * 2.0f;
327  gain = 1.0f / max_ff(gain, FLT_EPSILON);
328  offset = gain * (brightness - delta);
329  }
330  else {
331  delta *= -1;
332  gain = max_ff(1.0f - delta * 2.0f, 0.0f);
333  offset = gain * brightness + delta;
334  }
335  }
336 
337  Mesh *me;
338  if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
339  (ED_mesh_color_ensure(me, nullptr) == false)) {
340  return OPERATOR_CANCELLED;
341  }
342 
344  for (int i = 0; i < 3; i++) {
345  color[i] = gain * color[i] + offset;
346  }
347  });
348 
350 
351  return OPERATOR_FINISHED;
352 }
353 
355 {
356  PropertyRNA *prop;
357 
358  /* identifiers */
359  ot->name = "Vertex Paint Brightness/Contrast";
360  ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
361  ot->description = "Adjust vertex color brightness/contrast";
362 
363  /* api callbacks */
366 
367  /* flags */
369 
370  /* params */
371  const float min = -100, max = +100;
372  prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
373  prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
374  RNA_def_property_ui_range(prop, min, max, 1, 1);
375 }
376 
378 {
379  Object *obact = CTX_data_active_object(C);
380 
381  const float hue = RNA_float_get(op->ptr, "h");
382  const float sat = RNA_float_get(op->ptr, "s");
383  const float val = RNA_float_get(op->ptr, "v");
384 
385  Mesh *me;
386  if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
387  (ED_mesh_color_ensure(me, nullptr) == false)) {
388  return OPERATOR_CANCELLED;
389  }
390 
392  float hsv[3];
393  rgb_to_hsv_v(color, hsv);
394 
395  hsv[0] += (hue - 0.5f);
396  if (hsv[0] > 1.0f) {
397  hsv[0] -= 1.0f;
398  }
399  else if (hsv[0] < 0.0f) {
400  hsv[0] += 1.0f;
401  }
402  hsv[1] *= sat;
403  hsv[2] *= val;
404 
405  hsv_to_rgb_v(hsv, color);
406  });
407 
409 
410  return OPERATOR_FINISHED;
411 }
412 
414 {
415  /* identifiers */
416  ot->name = "Vertex Paint Hue Saturation Value";
417  ot->idname = "PAINT_OT_vertex_color_hsv";
418  ot->description = "Adjust vertex color HSV values";
419 
420  /* api callbacks */
423 
424  /* flags */
426 
427  /* params */
428  RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
429  RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
430  RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
431 }
432 
434 {
435  Object *obact = CTX_data_active_object(C);
436 
437  Mesh *me;
438  if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
439  (ED_mesh_color_ensure(me, nullptr) == false)) {
440  return OPERATOR_CANCELLED;
441  }
442 
444  for (int i = 0; i < 3; i++) {
445  color[i] = 1.0f - color[i];
446  }
447  });
448 
450 
451  return OPERATOR_FINISHED;
452 }
453 
455 {
456  /* identifiers */
457  ot->name = "Vertex Paint Invert";
458  ot->idname = "PAINT_OT_vertex_color_invert";
459  ot->description = "Invert RGB values";
460 
461  /* api callbacks */
464 
465  /* flags */
467 }
468 
470 {
471  Object *obact = CTX_data_active_object(C);
472 
473  const float gain = RNA_float_get(op->ptr, "gain");
474  const float offset = RNA_float_get(op->ptr, "offset");
475 
476  Mesh *me;
477  if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
478  (ED_mesh_color_ensure(me, nullptr) == false)) {
479  return OPERATOR_CANCELLED;
480  }
481 
483  for (int i = 0; i < 3; i++) {
484  color[i] = gain * (color[i] + offset);
485  }
486  });
487 
489 
490  return OPERATOR_FINISHED;
491 }
492 
494 {
495  /* identifiers */
496  ot->name = "Vertex Paint Levels";
497  ot->idname = "PAINT_OT_vertex_color_levels";
498  ot->description = "Adjust levels of vertex colors";
499 
500  /* api callbacks */
503 
504  /* flags */
506 
507  /* params */
509  ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
511  ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
512 }
513 
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:29
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
struct CustomDataLayer * BKE_id_attributes_active_color_get(const struct ID *id)
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
support for deformation groups and hooks.
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
@ BKE_MESH_BATCH_DIRTY_ALL
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition: math_color.c:49
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Definition: math_color.c:232
#define UNUSED(x)
#define ELEM(...)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_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.cc:423
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its hue
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_DRAW
Definition: WM_types.h:410
#define NC_OBJECT
Definition: WM_types.h:329
const CPPType & type() const
void materialize(void *dst) const
void set_all(const void *src)
GVArray adapt_domain(const GVArray &varray, const eAttrDomain from_domain, const eAttrDomain to_domain) const
int domain_size(const eAttrDomain domain) const
std::optional< AttributeMetaData > lookup_meta_data(const AttributeIDRef &attribute_id) const
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id)
static float verts[][3]
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_gpu_kernel_postfix int ccl_global int * indices
static char faces[256]
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
AttributeAccessor mesh_attributes(const Mesh &mesh)
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
Definition: customdata.cc:5337
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
IndexMask find_indices_from_virtual_array(IndexMask indices_to_check, const VArray< bool > &virtual_array, int64_t parallel_grain_size, Vector< int64_t > &r_indices)
Definition: index_mask.cc:201
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition: BLI_color.hh:346
bool vertex_paint_mode_poll(struct bContext *C)
static bool vertex_color_smooth(Object *ob)
static IndexMask get_selected_indices(const Mesh &mesh, const eAttrDomain domain, Vector< int64_t > &indices)
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 tag_object_after_update(Object *object)
static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask selection)
static bool vertex_paint_from_weight(Object *ob)
void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
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:3836
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
Definition: rna_define.c:1664
#define min(a, b)
Definition: sort.c:35
struct MVert * mvert
struct MDeformVert * dvert
ListBase vertex_group_names
char editflag
int totvert
int totpoly
int vertex_group_active_index
struct MPoly * mpoly
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct PointerRNA * ptr
float max
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479