Blender  V2.93
sculpt_filter_color.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  * The Original Code is Copyright (C) 2020 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_blenlib.h"
27 #include "BLI_hash.h"
28 #include "BLI_math.h"
29 #include "BLI_math_color_blend.h"
30 #include "BLI_task.h"
31 
32 #include "DNA_mesh_types.h"
33 #include "DNA_meshdata_types.h"
34 
35 #include "BKE_brush.h"
36 #include "BKE_colortools.h"
37 #include "BKE_context.h"
38 #include "BKE_mesh.h"
39 #include "BKE_mesh_mapping.h"
40 #include "BKE_object.h"
41 #include "BKE_paint.h"
42 #include "BKE_pbvh.h"
43 #include "BKE_scene.h"
44 
45 #include "IMB_colormanagement.h"
46 
47 #include "DEG_depsgraph.h"
48 
49 #include "WM_api.h"
50 #include "WM_message.h"
51 #include "WM_toolsystem.h"
52 #include "WM_types.h"
53 
54 #include "ED_object.h"
55 #include "ED_screen.h"
56 #include "ED_sculpt.h"
57 #include "paint_intern.h"
58 #include "sculpt_intern.h"
59 
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62 
63 #include "UI_interface.h"
64 
65 #include "bmesh.h"
66 
67 #include <math.h>
68 #include <stdlib.h>
69 
82 
84  {COLOR_FILTER_FILL, "FILL", 0, "Fill", "Fill with a specific color"},
85  {COLOR_FILTER_HUE, "HUE", 0, "Hue", "Change hue"},
86  {COLOR_FILTER_SATURATION, "SATURATION", 0, "Saturation", "Change saturation"},
87  {COLOR_FILTER_VALUE, "VALUE", 0, "Value", "Change value"},
88 
89  {COLOR_FILTER_BRIGHTNESS, "BRIGHTNESS", 0, "Brightness", "Change brightness"},
90  {COLOR_FILTER_CONTRAST, "CONTRAST", 0, "Contrast", "Change contrast"},
91 
92  {COLOR_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth colors"},
93 
94  {COLOR_FILTER_RED, "RED", 0, "Red", "Change red channel"},
95  {COLOR_FILTER_GREEN, "GREEN", 0, "Green", "Change green channel"},
96  {COLOR_FILTER_BLUE, "BLUE", 0, "Blue", "Change blue channel"},
97  {0, NULL, 0, NULL, NULL},
98 };
99 
100 static void color_filter_task_cb(void *__restrict userdata,
101  const int n,
102  const TaskParallelTLS *__restrict UNUSED(tls))
103 {
104  SculptThreadedTaskData *data = userdata;
105  SculptSession *ss = data->ob->sculpt;
106 
107  const int mode = data->filter_type;
108 
109  SculptOrigVertData orig_data;
110  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
111 
112  PBVHVertexIter vd;
113  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
114  SCULPT_orig_vert_data_update(&orig_data, &vd);
115  float orig_color[3], final_color[4], hsv_color[3];
116  int hue;
117  float brightness, contrast, gain, delta, offset;
118  float fade = vd.mask ? *vd.mask : 0.0f;
119  fade = 1.0f - fade;
120  fade *= data->filter_strength;
122  if (fade == 0.0f) {
123  continue;
124  }
125 
126  copy_v3_v3(orig_color, orig_data.col);
127 
128  switch (mode) {
129  case COLOR_FILTER_FILL: {
130  float fill_color_rgba[4];
131  copy_v3_v3(fill_color_rgba, data->filter_fill_color);
132  fill_color_rgba[3] = 1.0f;
133  fade = clamp_f(fade, 0.0f, 1.0f);
134  mul_v4_fl(fill_color_rgba, fade);
135  blend_color_mix_float(final_color, orig_data.col, fill_color_rgba);
136  break;
137  }
138  case COLOR_FILTER_HUE:
139  rgb_to_hsv_v(orig_color, hsv_color);
140  hue = hsv_color[0] + fade;
141  hsv_color[0] = fabs((hsv_color[0] + fade) - hue);
142  hsv_to_rgb_v(hsv_color, final_color);
143  break;
145  rgb_to_hsv_v(orig_color, hsv_color);
146  hsv_color[1] = clamp_f(hsv_color[1] + fade, 0.0f, 1.0f);
147  hsv_to_rgb_v(hsv_color, final_color);
148  break;
149  case COLOR_FILTER_VALUE:
150  rgb_to_hsv_v(orig_color, hsv_color);
151  hsv_color[2] = clamp_f(hsv_color[2] + fade, 0.0f, 1.0f);
152  hsv_to_rgb_v(hsv_color, final_color);
153  break;
154  case COLOR_FILTER_RED:
155  orig_color[0] = clamp_f(orig_color[0] + fade, 0.0f, 1.0f);
156  copy_v3_v3(final_color, orig_color);
157  break;
158  case COLOR_FILTER_GREEN:
159  orig_color[1] = clamp_f(orig_color[1] + fade, 0.0f, 1.0f);
160  copy_v3_v3(final_color, orig_color);
161  break;
162  case COLOR_FILTER_BLUE:
163  orig_color[2] = clamp_f(orig_color[2] + fade, 0.0f, 1.0f);
164  copy_v3_v3(final_color, orig_color);
165  break;
167  fade = clamp_f(fade, -1.0f, 1.0f);
168  brightness = fade;
169  contrast = 0;
170  delta = contrast / 2.0f;
171  gain = 1.0f - delta * 2.0f;
172  delta *= -1;
173  offset = gain * (brightness + delta);
174  for (int i = 0; i < 3; i++) {
175  final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f);
176  }
177  break;
179  fade = clamp_f(fade, -1.0f, 1.0f);
180  brightness = 0;
181  contrast = fade;
182  delta = contrast / 2.0f;
183  gain = 1.0f - delta * 2.0f;
184  if (contrast > 0) {
185  gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
186  offset = gain * (brightness - delta);
187  }
188  else {
189  delta *= -1;
190  offset = gain * (brightness + delta);
191  }
192  for (int i = 0; i < 3; i++) {
193  final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f);
194  }
195  break;
196  case COLOR_FILTER_SMOOTH: {
197  fade = clamp_f(fade, -1.0f, 1.0f);
198  float smooth_color[4];
199  SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
200  blend_color_interpolate_float(final_color, vd.col, smooth_color, fade);
201  break;
202  }
203  }
204 
205  copy_v3_v3(vd.col, final_color);
206 
207  if (vd.mvert) {
209  }
210  }
213 }
214 
215 static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
216 {
218  SculptSession *ss = ob->sculpt;
220  const int mode = RNA_enum_get(op->ptr, "type");
221  float filter_strength = RNA_float_get(op->ptr, "strength");
222 
223  if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
227  return OPERATOR_FINISHED;
228  }
229 
230  if (event->type != MOUSEMOVE) {
231  return OPERATOR_RUNNING_MODAL;
232  }
233 
234  const float len = event->prevclickx - event->x;
235  filter_strength = filter_strength * -len * 0.001f;
236 
237  float fill_color[3];
238  RNA_float_get_array(op->ptr, "fill_color", fill_color);
240 
242  .sd = sd,
243  .ob = ob,
244  .nodes = ss->filter_cache->nodes,
245  .filter_type = mode,
246  .filter_strength = filter_strength,
247  .filter_fill_color = fill_color,
248  };
249 
250  TaskParallelSettings settings;
252 
255 
257 
258  return OPERATOR_RUNNING_MODAL;
259 }
260 
261 static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
262 {
265  SculptSession *ss = ob->sculpt;
266  int mode = RNA_enum_get(op->ptr, "type");
267  PBVH *pbvh = ob->sculpt->pbvh;
268 
269  const bool use_automasking = SCULPT_is_automasking_enabled(sd, ss, NULL);
270  if (use_automasking) {
271  /* Update the active face set manually as the paint cursor is not enabled when using the Mesh
272  * Filter Tool. */
273  float mouse[2];
275  mouse[0] = event->mval[0];
276  mouse[1] = event->mval[1];
277  SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
278  }
279 
280  /* Disable for multires and dyntopo for now */
281  if (!ss->pbvh) {
282  return OPERATOR_CANCELLED;
283  }
284  if (BKE_pbvh_type(pbvh) != PBVH_FACES) {
285  return OPERATOR_CANCELLED;
286  }
287 
288  if (!ss->vcol) {
289  return OPERATOR_CANCELLED;
290  }
291 
292  SCULPT_undo_push_begin(ob, "color filter");
293 
295 
296  /* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
297  * earlier steps modifying the data. */
299  const bool needs_topology_info = mode == COLOR_FILTER_SMOOTH || use_automasking;
300  BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_topology_info, false, true);
301 
302  if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_topology_info && !ob->sculpt->pmap) {
303  return OPERATOR_CANCELLED;
304  }
305 
307  FilterCache *filter_cache = ss->filter_cache;
308  filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
309  filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob);
310 
312  return OPERATOR_RUNNING_MODAL;
313 }
314 
316 {
317  /* identifiers */
318  ot->name = "Filter Color";
319  ot->idname = "SCULPT_OT_color_filter";
320  ot->description = "Applies a filter to modify the current sculpt vertex colors";
321 
322  /* api callbacks */
326 
328 
329  /* rna */
330  RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter Type", "");
332  ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f);
333 
335  ot->srna, "fill_color", 3, NULL, 0.0f, FLT_MAX, "Fill Color", "", 0.0f, 1.0f);
337 }
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1208
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 need_colors)
Definition: paint.c:1817
#define SCULPT_FACE_SET_NONE
Definition: BKE_paint.h:230
void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
Definition: paint.c:1800
A BVH for high poly meshes.
#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode)
Definition: BKE_pbvh.h:384
void BKE_pbvh_node_mark_update_color(PBVHNode *node)
Definition: pbvh.c:1743
PBVHType BKE_pbvh_type(const PBVH *pbvh)
Definition: pbvh.c:1661
#define BKE_pbvh_vertex_iter_end
Definition: BKE_pbvh.h:457
#define PBVH_ITER_UNIQUE
Definition: BKE_pbvh.h:335
@ PBVH_FACES
Definition: BKE_pbvh.h:210
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, bool use_threading, int totnode)
Definition: pbvh.c:3042
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:68
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Definition: math_color.c:254
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 copy_v3_v3(float r[3], const float a[3])
void BLI_task_parallel_range(const int start, const int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:110
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:231
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
@ ME_VERT_PBVH_UPDATE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
Read Guarded memory(de)allocation.
@ PROP_COLOR_GAMMA
Definition: RNA_types.h:151
#define C
Definition: RandGen.cpp:39
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define KM_RELEASE
Definition: WM_types.h:243
const Depsgraph * depsgraph
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
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
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:3911
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
Definition: rna_define.c:1563
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:3771
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
Definition: sculpt.c:1310
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mouse[2], bool use_sampled_normal)
Definition: sculpt.c:7452
void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
Definition: sculpt.c:7819
void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
Definition: sculpt.c:7759
bool SCULPT_vertex_colors_poll(bContext *C)
Definition: sculpt.c:6607
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
Definition: sculpt.c:1300
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
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:1383
@ SCULPT_UPDATE_COLOR
Definition: sculpt_intern.h:61
void SCULPT_undo_push_end(void)
Definition: sculpt_undo.c:1400
void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index)
@ SCULPT_UNDO_COLOR
AutomaskingCache * automasking
PBVHNode ** nodes
struct SculptSession * sculpt
struct MVert * mvert
Definition: BKE_pbvh.h:372
float * col
Definition: BKE_pbvh.h:378
float * mask
Definition: BKE_pbvh.h:377
const float * col
struct MPropCol * vcol
Definition: BKE_paint.h:469
struct MeshElemMap * pmap
Definition: BKE_paint.h:474
struct FilterCache * filter_cache
Definition: BKE_paint.h:519
struct PBVH * pbvh
Definition: BKE_paint.h:504
short val
Definition: WM_types.h:579
short type
Definition: WM_types.h:577
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
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
struct PointerRNA * ptr
CCL_NAMESPACE_BEGIN ccl_device float fade(float t)
Definition: svm_noise.h:37
ccl_device_inline float2 fabs(const float2 &a)
uint len
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ MOUSEMOVE
@ LEFTMOUSE
wmOperatorType * ot
Definition: wm_files.c:3156