Blender  V3.3
sculpt_filter_color.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_blenlib.h"
11 #include "BLI_hash.h"
12 #include "BLI_math.h"
13 #include "BLI_math_color_blend.h"
14 #include "BLI_task.h"
15 
16 #include "DNA_mesh_types.h"
17 #include "DNA_meshdata_types.h"
18 
19 #include "BKE_brush.h"
20 #include "BKE_colortools.h"
21 #include "BKE_context.h"
22 #include "BKE_mesh.h"
23 #include "BKE_mesh_mapping.h"
24 #include "BKE_object.h"
25 #include "BKE_paint.h"
26 #include "BKE_pbvh.h"
27 #include "BKE_report.h"
28 #include "BKE_scene.h"
29 
30 #include "IMB_colormanagement.h"
31 
32 #include "DEG_depsgraph.h"
33 
34 #include "WM_api.h"
35 #include "WM_message.h"
36 #include "WM_toolsystem.h"
37 #include "WM_types.h"
38 
39 #include "ED_object.h"
40 #include "ED_paint.h"
41 #include "ED_screen.h"
42 #include "ED_sculpt.h"
43 #include "paint_intern.h"
44 #include "sculpt_intern.h"
45 
46 #include "RNA_access.h"
47 #include "RNA_define.h"
48 
49 #include "UI_interface.h"
50 
51 #include "bmesh.h"
52 
53 #include <math.h>
54 #include <stdlib.h>
55 
68 
70  {COLOR_FILTER_FILL, "FILL", 0, "Fill", "Fill with a specific color"},
71  {COLOR_FILTER_HUE, "HUE", 0, "Hue", "Change hue"},
72  {COLOR_FILTER_SATURATION, "SATURATION", 0, "Saturation", "Change saturation"},
73  {COLOR_FILTER_VALUE, "VALUE", 0, "Value", "Change value"},
74 
75  {COLOR_FILTER_BRIGHTNESS, "BRIGHTNESS", 0, "Brightness", "Change brightness"},
76  {COLOR_FILTER_CONTRAST, "CONTRAST", 0, "Contrast", "Change contrast"},
77 
78  {COLOR_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth colors"},
79 
80  {COLOR_FILTER_RED, "RED", 0, "Red", "Change red channel"},
81  {COLOR_FILTER_GREEN, "GREEN", 0, "Green", "Change green channel"},
82  {COLOR_FILTER_BLUE, "BLUE", 0, "Blue", "Change blue channel"},
83  {0, NULL, 0, NULL, NULL},
84 };
85 
86 static void color_filter_task_cb(void *__restrict userdata,
87  const int n,
88  const TaskParallelTLS *__restrict UNUSED(tls))
89 {
90  SculptThreadedTaskData *data = userdata;
91  SculptSession *ss = data->ob->sculpt;
92 
93  const int mode = data->filter_type;
94 
95  SculptOrigVertData orig_data;
96  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
97 
98  PBVHVertexIter vd;
100  SCULPT_orig_vert_data_update(&orig_data, &vd);
101  float orig_color[3], final_color[4], hsv_color[3];
102  int hue;
103  float brightness, contrast, gain, delta, offset;
104  float fade = vd.mask ? *vd.mask : 0.0f;
105  fade = 1.0f - fade;
106  fade *= data->filter_strength;
108  if (fade == 0.0f) {
109  continue;
110  }
111 
112  copy_v3_v3(orig_color, orig_data.col);
113  final_color[3] = orig_data.col[3]; /* Copy alpha */
114 
115  switch (mode) {
116  case COLOR_FILTER_FILL: {
117  float fill_color_rgba[4];
118  copy_v3_v3(fill_color_rgba, data->filter_fill_color);
119  fill_color_rgba[3] = 1.0f;
120  fade = clamp_f(fade, 0.0f, 1.0f);
121  mul_v4_fl(fill_color_rgba, fade);
122  blend_color_mix_float(final_color, orig_data.col, fill_color_rgba);
123  break;
124  }
125  case COLOR_FILTER_HUE:
126  rgb_to_hsv_v(orig_color, hsv_color);
127  hue = hsv_color[0];
128  hsv_color[0] = fmod((hsv_color[0] + fabs(fade)) - hue, 1);
129  hsv_to_rgb_v(hsv_color, final_color);
130  break;
132  rgb_to_hsv_v(orig_color, hsv_color);
133 
134  if (hsv_color[1] > 0.001f) {
135  hsv_color[1] = clamp_f(hsv_color[1] + fade * hsv_color[1], 0.0f, 1.0f);
136  hsv_to_rgb_v(hsv_color, final_color);
137  }
138  else {
139  copy_v3_v3(final_color, orig_color);
140  }
141  break;
142  case COLOR_FILTER_VALUE:
143  rgb_to_hsv_v(orig_color, hsv_color);
144  hsv_color[2] = clamp_f(hsv_color[2] + fade, 0.0f, 1.0f);
145  hsv_to_rgb_v(hsv_color, final_color);
146  break;
147  case COLOR_FILTER_RED:
148  orig_color[0] = clamp_f(orig_color[0] + fade, 0.0f, 1.0f);
149  copy_v3_v3(final_color, orig_color);
150  break;
151  case COLOR_FILTER_GREEN:
152  orig_color[1] = clamp_f(orig_color[1] + fade, 0.0f, 1.0f);
153  copy_v3_v3(final_color, orig_color);
154  break;
155  case COLOR_FILTER_BLUE:
156  orig_color[2] = clamp_f(orig_color[2] + fade, 0.0f, 1.0f);
157  copy_v3_v3(final_color, orig_color);
158  break;
160  fade = clamp_f(fade, -1.0f, 1.0f);
161  brightness = fade;
162  contrast = 0;
163  delta = contrast / 2.0f;
164  gain = 1.0f - delta * 2.0f;
165  delta *= -1;
166  offset = gain * (brightness + delta);
167  for (int i = 0; i < 3; i++) {
168  final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f);
169  }
170  break;
172  fade = clamp_f(fade, -1.0f, 1.0f);
173  brightness = 0;
174  contrast = fade;
175  delta = contrast / 2.0f;
176  gain = 1.0f - delta * 2.0f;
177  if (contrast > 0) {
178  gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
179  offset = gain * (brightness - delta);
180  }
181  else {
182  delta *= -1;
183  offset = gain * (brightness + delta);
184  }
185  for (int i = 0; i < 3; i++) {
186  final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f);
187  }
188  break;
189  case COLOR_FILTER_SMOOTH: {
190  fade = clamp_f(fade, -1.0f, 1.0f);
191  float smooth_color[4];
192  SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
193 
194  float col[4];
196 
197  if (fade < 0.0f) {
198  interp_v4_v4v4(smooth_color, smooth_color, col, 0.5f);
199  }
200 
201  bool copy_alpha = col[3] == smooth_color[3];
202 
203  if (fade < 0.0f) {
204  float delta_color[4];
205 
206  /* Unsharp mask. */
207  copy_v4_v4(delta_color, ss->filter_cache->pre_smoothed_color[vd.index]);
208  sub_v4_v4(delta_color, smooth_color);
209 
210  copy_v4_v4(final_color, col);
211  madd_v4_v4fl(final_color, delta_color, fade);
212  }
213  else {
214  blend_color_interpolate_float(final_color, col, smooth_color, fade);
215  }
216 
217  CLAMP4(final_color, 0.0f, 1.0f);
218 
219  /* Prevent accumulated numeric error from corrupting alpha. */
220  if (copy_alpha) {
221  final_color[3] = smooth_color[3];
222  }
223  break;
224  }
225  }
226 
227  SCULPT_vertex_color_set(ss, vd.index, final_color);
228  }
231 }
232 
234 {
235  int totvert = SCULPT_vertex_count_get(ss);
236 
237  if (!ss->filter_cache->pre_smoothed_color) {
239  totvert, sizeof(float) * 4, "ss->filter_cache->pre_smoothed_color");
240  }
241 
242  for (int i = 0; i < totvert; i++) {
244  }
245 
246  for (int iteration = 0; iteration < 2; iteration++) {
247  for (int i = 0; i < totvert; i++) {
248  float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f};
249  int total = 0;
250 
253  float col[4] = {0};
254 
256 
257  add_v4_v4(avg, col);
258  total++;
259  }
261 
262  if (total > 0) {
263  mul_v4_fl(avg, 1.0f / (float)total);
266  avg,
267  0.5f);
268  }
269  }
270  }
271 }
272 
273 static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
274 {
276  SculptSession *ss = ob->sculpt;
278  const int mode = RNA_enum_get(op->ptr, "type");
279  float filter_strength = RNA_float_get(op->ptr, "strength");
280 
281  if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
285  return OPERATOR_FINISHED;
286  }
287 
288  if (event->type != MOUSEMOVE) {
289  return OPERATOR_RUNNING_MODAL;
290  }
291 
292  const float len = event->prev_press_xy[0] - event->xy[0];
293  filter_strength = filter_strength * -len * 0.001f;
294 
295  float fill_color[3];
296  RNA_float_get_array(op->ptr, "fill_color", fill_color);
297  IMB_colormanagement_srgb_to_scene_linear_v3(fill_color, fill_color);
298 
299  if (filter_strength < 0.0 && !ss->filter_cache->pre_smoothed_color) {
301  }
302 
304  .sd = sd,
305  .ob = ob,
306  .nodes = ss->filter_cache->nodes,
307  .filter_type = mode,
308  .filter_strength = filter_strength,
309  .filter_fill_color = fill_color,
310  };
311 
312  TaskParallelSettings settings;
314 
317 
319 
320  return OPERATOR_RUNNING_MODAL;
321 }
322 
323 static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
324 {
327  View3D *v3d = CTX_wm_view3d(C);
328  SculptSession *ss = ob->sculpt;
329  PBVH *pbvh = ob->sculpt->pbvh;
330  if (v3d->shading.type == OB_SOLID) {
332  }
333 
334  const bool use_automasking = SCULPT_is_automasking_enabled(sd, ss, NULL);
335  if (use_automasking) {
336  /* Update the active face set manually as the paint cursor is not enabled when using the Mesh
337  * Filter Tool. */
338  float mval_fl[2] = {UNPACK2(event->mval)};
340  SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
341  }
342 
343  /* Disable for multires and dyntopo for now */
344  if (!ss->pbvh || !SCULPT_handles_colors_report(ss, op->reports)) {
345  return OPERATOR_CANCELLED;
346  }
347 
348  SCULPT_undo_push_begin(ob, "color filter");
350 
351  /* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
352  * earlier steps modifying the data. */
354  BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
355 
356  if (BKE_pbvh_type(pbvh) == PBVH_FACES && !ob->sculpt->pmap) {
357  return OPERATOR_CANCELLED;
358  }
359 
361  FilterCache *filter_cache = ss->filter_cache;
362  filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
363  filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob);
365 
367  return OPERATOR_RUNNING_MODAL;
368 }
369 
371 {
372  /* identifiers */
373  ot->name = "Filter Color";
374  ot->idname = "SCULPT_OT_color_filter";
375  ot->description = "Applies a filter to modify the active color attribute";
376 
377  /* api callbacks */
381 
383 
384  /* rna */
385  RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter Type", "");
387  ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f);
388 
390  ot->srna, "fill_color", 3, NULL, 0.0f, FLT_MAX, "Fill Color", "", 0.0f, 1.0f);
392 }
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
General operations, lookup, etc. for blender objects.
void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph, struct Object *ob_orig, bool need_pmap, bool need_mask, bool is_paint_tool)
Definition: paint.c:1914
#define SCULPT_FACE_SET_NONE
Definition: BKE_paint.h:267
void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
Definition: paint.c:1880
A BVH for high poly meshes.
#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode)
Definition: BKE_pbvh.h:439
void BKE_pbvh_node_mark_update_color(PBVHNode *node)
Definition: pbvh.c:1880
PBVHType BKE_pbvh_type(const PBVH *pbvh)
Definition: pbvh.c:1798
#define BKE_pbvh_vertex_iter_end
Definition: BKE_pbvh.h:509
#define PBVH_ITER_UNIQUE
Definition: BKE_pbvh.h:391
@ PBVH_FACES
Definition: BKE_pbvh.h:234
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, bool use_threading, int totnode)
Definition: pbvh.c:3211
MINLINE float clamp_f(float value, float min, float max)
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
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t)
Definition: math_vector.c:38
MINLINE void sub_v4_v4(float r[4], const float a[4])
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f)
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define UNPACK2(a)
#define UNUSED(x)
#define CLAMP4(vec, b, c)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ OB_SOLID
@ V3D_SHADING_VERTEX_COLOR
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void ED_paint_tool_update_sticky_shading_color(struct bContext *C, struct Object *ob)
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
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
@ PROP_COLOR_GAMMA
Definition: RNA_types.h:165
#define C
Definition: RandGen.cpp:25
@ KM_RELEASE
Definition: WM_types.h:268
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
const Depsgraph * depsgraph
int len
Definition: draw_manager.c:108
uint col
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
CCL_NAMESPACE_BEGIN ccl_device float fade(float t)
Definition: noise.h:15
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
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
PropertyRNA * RNA_def_float_color(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3922
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
Definition: rna_define.c:1534
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
int SCULPT_vertex_count_get(SculptSession *ss)
Definition: sculpt.c:111
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
Definition: sculpt.c:1300
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node, SculptUndoType type)
Definition: sculpt.c:1290
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
Definition: sculpt.c:4835
void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
Definition: sculpt.c:5212
void SCULPT_vertex_color_set(SculptSession *ss, int index, const float color[4])
Definition: sculpt.c:166
void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
Definition: sculpt.c:5144
void SCULPT_vertex_color_get(const SculptSession *ss, int index, float r_color[4])
Definition: sculpt.c:161
bool SCULPT_mode_poll(bContext *C)
Definition: sculpt.c:3957
bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
Definition: sculpt.c:5303
float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert)
AutomaskingCache * SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob)
bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br)
static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void color_filter_task_cb(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
eSculptColorFilterTypes
@ COLOR_FILTER_HUE
@ COLOR_FILTER_BLUE
@ COLOR_FILTER_VALUE
@ COLOR_FILTER_GREEN
@ COLOR_FILTER_SMOOTH
@ COLOR_FILTER_RED
@ COLOR_FILTER_BRIGHTNESS
@ COLOR_FILTER_CONTRAST
@ COLOR_FILTER_SATURATION
@ COLOR_FILTER_FILL
static void sculpt_color_presmooth_init(SculptSession *ss)
void SCULPT_OT_color_filter(struct wmOperatorType *ot)
static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static EnumPropertyItem prop_color_filter_types[]
void SCULPT_filter_cache_init(bContext *C, Object *ob, Sculpt *sd, const int undo_type)
void SCULPT_filter_cache_free(SculptSession *ss)
void SCULPT_undo_push_begin(struct Object *ob, const char *name)
Definition: sculpt_undo.c:1545
void SCULPT_undo_push_end(struct Object *ob)
Definition: sculpt_undo.c:1575
#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator)
@ SCULPT_UPDATE_COLOR
Definition: sculpt_intern.h:48
#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator)
void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index)
@ SCULPT_UNDO_COLOR
AutomaskingCache * automasking
PBVHNode ** nodes
float(* pre_smoothed_color)[4]
struct SculptSession * sculpt
float * mask
Definition: BKE_pbvh.h:433
const float * col
Definition: sculpt_intern.h:90
struct MeshElemMap * pmap
Definition: BKE_paint.h:516
struct FilterCache * filter_cache
Definition: BKE_paint.h:564
struct PBVH * pbvh
Definition: BKE_paint.h:550
View3DShading shading
short val
Definition: WM_types.h:680
int mval[2]
Definition: WM_types.h:684
short type
Definition: WM_types.h:678
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
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
struct ReportList * reports
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ MOUSEMOVE
@ LEFTMOUSE
wmOperatorType * ot
Definition: wm_files.c:3479