Blender V4.3
sculpt_filter_color.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
12#include "BLI_math_color.h"
14#include "BLI_math_vector.hh"
15#include "BLI_task.h"
16
17#include "BLT_translation.hh"
18
19#include "BKE_attribute.hh"
20#include "BKE_context.hh"
21#include "BKE_layer.hh"
22#include "BKE_mesh.hh"
23#include "BKE_paint.hh"
24#include "BKE_pbvh_api.hh"
25
27
28#include "WM_api.hh"
29#include "WM_types.hh"
30
31#include "ED_paint.hh"
32
33#include "mesh_brush_common.hh"
34#include "sculpt_automask.hh"
35#include "sculpt_color.hh"
36#include "sculpt_filter.hh"
37#include "sculpt_intern.hh"
38#include "sculpt_smooth.hh"
39#include "sculpt_undo.hh"
40
41#include "RNA_access.hh"
42#include "RNA_define.hh"
43
44#include "UI_interface.hh"
45#include "UI_resources.hh"
46
47#include <cmath>
48#include <cstdlib>
49
51
52enum class FilterType {
53 Fill = 0,
54 Hue,
56 Value,
59 Red,
60 Green,
61 Blue,
62 Smooth,
63};
64
65static const float fill_filter_default_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
66
68 {int(FilterType::Fill), "FILL", 0, "Fill", "Fill with a specific color"},
69 {int(FilterType::Hue), "HUE", 0, "Hue", "Change hue"},
70 {int(FilterType::Saturation), "SATURATION", 0, "Saturation", "Change saturation"},
71 {int(FilterType::Value), "VALUE", 0, "Value", "Change value"},
72 {int(FilterType::Brightness), "BRIGHTNESS", 0, "Brightness", "Change brightness"},
73 {int(FilterType::Contrast), "CONTRAST", 0, "Contrast", "Change contrast"},
74 {int(FilterType::Smooth), "SMOOTH", 0, "Smooth", "Smooth colors"},
75 {int(FilterType::Red), "RED", 0, "Red", "Change red channel"},
76 {int(FilterType::Green), "GREEN", 0, "Green", "Change green channel"},
77 {int(FilterType::Blue), "BLUE", 0, "Blue", "Change blue channel"},
78 {0, nullptr, 0, nullptr, nullptr},
79};
80
88
90 const float min,
91 const float max)
92{
93 for (float &factor : factors) {
94 factor = std::clamp(factor, min, max);
95 }
96}
97
98static void color_filter_task(const Depsgraph &depsgraph,
99 Object &ob,
100 const OffsetIndices<int> faces,
101 const Span<int> corner_verts,
102 const GroupedSpan<int> vert_to_face_map,
103 const MeshAttributeData &attribute_data,
104 const FilterType mode,
105 const float filter_strength,
106 const float *filter_fill_color,
107 const bke::pbvh::MeshNode &node,
108 LocalData &tls,
109 bke::GSpanAttributeWriter &color_attribute)
110{
111 SculptSession &ss = *ob.sculpt;
112
113 const Span<float4> orig_colors = orig_color_data_get_mesh(ob, node);
114
115 const Span<int> verts = node.verts();
116
117 tls.factors.resize(verts.size());
118 const MutableSpan<float> factors = tls.factors;
119 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
121 depsgraph, ob, ss.filter_cache->automasking.get(), node, verts, factors);
122 scale_factors(factors, filter_strength);
123
124 tls.new_colors.resize(verts.size());
125 const MutableSpan<float4> new_colors = tls.new_colors;
126
127 /* Copy alpha. */
128 for (const int i : verts.index_range()) {
129 new_colors[i][3] = orig_colors[i][3];
130 }
131
132 switch (mode) {
133 case FilterType::Fill: {
134 clamp_factors(factors, 0.0f, 1.0f);
135 for (const int i : verts.index_range()) {
136 float fill_color_rgba[4];
137 copy_v3_v3(fill_color_rgba, filter_fill_color);
138 fill_color_rgba[3] = 1.0f;
139 mul_v4_fl(fill_color_rgba, factors[i]);
140 blend_color_mix_float(new_colors[i], orig_colors[i], fill_color_rgba);
141 }
142 break;
143 }
144 case FilterType::Hue: {
145 for (const int i : verts.index_range()) {
146 float3 hsv_color;
147 rgb_to_hsv_v(orig_colors[i], hsv_color);
148 const float hue = hsv_color[0];
149 hsv_color[0] = fmod((hsv_color[0] + fabs(factors[i])) - hue, 1);
150 hsv_to_rgb_v(hsv_color, new_colors[i]);
151 }
152 break;
153 }
154 case FilterType::Saturation: {
155 for (const int i : verts.index_range()) {
156 float3 hsv_color;
157 rgb_to_hsv_v(orig_colors[i], hsv_color);
158
159 if (hsv_color[1] > 0.001f) {
160 hsv_color[1] = std::clamp(hsv_color[1] + factors[i] * hsv_color[1], 0.0f, 1.0f);
161 hsv_to_rgb_v(hsv_color, new_colors[i]);
162 }
163 else {
164 copy_v3_v3(new_colors[i], orig_colors[i]);
165 }
166 }
167 break;
168 }
169 case FilterType::Value: {
170 for (const int i : verts.index_range()) {
171 float3 hsv_color;
172 rgb_to_hsv_v(orig_colors[i], hsv_color);
173 hsv_color[2] = std::clamp(hsv_color[2] + factors[i], 0.0f, 1.0f);
174 hsv_to_rgb_v(hsv_color, new_colors[i]);
175 }
176 break;
177 }
178 case FilterType::Red: {
179 for (const int i : verts.index_range()) {
180 copy_v3_v3(new_colors[i], orig_colors[i]);
181 new_colors[i][0] = std::clamp(orig_colors[i][0] + factors[i], 0.0f, 1.0f);
182 }
183 break;
184 }
185 case FilterType::Green: {
186 for (const int i : verts.index_range()) {
187 copy_v3_v3(new_colors[i], orig_colors[i]);
188 new_colors[i][1] = std::clamp(orig_colors[i][1] + factors[i], 0.0f, 1.0f);
189 }
190 break;
191 }
192 case FilterType::Blue: {
193 for (const int i : verts.index_range()) {
194 copy_v3_v3(new_colors[i], orig_colors[i]);
195 new_colors[i][2] = std::clamp(orig_colors[i][2] + factors[i], 0.0f, 1.0f);
196 }
197 break;
198 }
199 case FilterType::Brightness: {
200 clamp_factors(factors, -1.0f, 1.0f);
201 for (const int i : verts.index_range()) {
202 const float brightness = factors[i];
203 const float contrast = 0;
204 float delta = contrast / 2.0f;
205 const float gain = 1.0f - delta * 2.0f;
206 delta *= -1;
207 const float offset = gain * (brightness + delta);
208 for (int component = 0; component < 3; component++) {
209 new_colors[i][component] = std::clamp(
210 gain * orig_colors[i][component] + offset, 0.0f, 1.0f);
211 }
212 }
213 break;
214 }
215 case FilterType::Contrast: {
216 clamp_factors(factors, -1.0f, 1.0f);
217 for (const int i : verts.index_range()) {
218 const float brightness = 0;
219 const float contrast = factors[i];
220 float delta = contrast / 2.0f;
221 float gain = 1.0f - delta * 2.0f;
222
223 float offset;
224 if (contrast > 0) {
225 gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
226 offset = gain * (brightness - delta);
227 }
228 else {
229 delta *= -1;
230 offset = gain * (brightness + delta);
231 }
232 for (int component = 0; component < 3; component++) {
233 new_colors[i][component] = std::clamp(
234 gain * orig_colors[i][component] + offset, 0.0f, 1.0f);
235 }
236 }
237 break;
238 }
239 case FilterType::Smooth: {
240 clamp_factors(factors, -1.0f, 1.0f);
241
242 tls.colors.resize(verts.size());
243 const MutableSpan<float4> colors = tls.colors;
244 for (const int i : verts.index_range()) {
245 colors[i] = color_vert_get(faces,
246 corner_verts,
247 vert_to_face_map,
248 color_attribute.span,
249 color_attribute.domain,
250 verts[i]);
251 }
252
253 tls.vert_neighbors.resize(verts.size());
254 calc_vert_neighbors(faces, corner_verts, vert_to_face_map, {}, verts, tls.vert_neighbors);
255 const Span<Vector<int>> neighbors = tls.vert_neighbors;
256
257 tls.average_colors.resize(verts.size());
258 const MutableSpan<float4> average_colors = tls.average_colors;
260 corner_verts,
261 vert_to_face_map,
262 color_attribute.span,
263 color_attribute.domain,
264 neighbors,
265 average_colors);
266
267 for (const int i : verts.index_range()) {
268 const int vert = verts[i];
269
270 if (factors[i] < 0.0f) {
271 interp_v4_v4v4(average_colors[i], average_colors[i], colors[i], 0.5f);
272 }
273
274 bool copy_alpha = colors[i][3] == average_colors[i][3];
275
276 if (factors[i] < 0.0f) {
277 float delta_color[4];
278
279 /* Unsharp mask. */
280 copy_v4_v4(delta_color, ss.filter_cache->pre_smoothed_color[vert]);
281 sub_v4_v4(delta_color, average_colors[i]);
282
283 copy_v4_v4(new_colors[i], colors[i]);
284 madd_v4_v4fl(new_colors[i], delta_color, factors[i]);
285 }
286 else {
287 blend_color_interpolate_float(new_colors[i], colors[i], average_colors[i], factors[i]);
288 }
289
290 new_colors[i] = math::clamp(new_colors[i], 0.0f, 1.0f);
291
292 /* Prevent accumulated numeric error from corrupting alpha. */
293 if (copy_alpha) {
294 new_colors[i][3] = average_colors[i][3];
295 }
296 }
297 break;
298 }
299 }
300
301 for (const int i : verts.index_range()) {
302 color_vert_set(faces,
303 corner_verts,
304 vert_to_face_map,
305 color_attribute.domain,
306 verts[i],
307 new_colors[i],
308 color_attribute.span);
309 }
310}
311
312static void sculpt_color_presmooth_init(const Mesh &mesh, Object &object)
313{
314 SculptSession &ss = *object.sculpt;
315 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
317 const IndexMask &node_mask = ss.filter_cache->node_mask;
318 const OffsetIndices<int> faces = mesh.faces();
319 const Span<int> corner_verts = mesh.corner_verts();
320 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
321 const bke::GAttributeReader color_attribute = active_color_attribute(mesh);
322 const GVArraySpan colors = *color_attribute;
323
324 if (ss.filter_cache->pre_smoothed_color.is_empty()) {
325 ss.filter_cache->pre_smoothed_color = Array<float4>(mesh.verts_num);
326 }
327 const MutableSpan<float4> pre_smoothed_color = ss.filter_cache->pre_smoothed_color;
328
329 node_mask.foreach_index(GrainSize(1), [&](const int i) {
330 for (const int vert : nodes[i].verts()) {
331 pre_smoothed_color[vert] = color_vert_get(
332 faces, corner_verts, vert_to_face_map, colors, color_attribute.domain, vert);
333 }
334 });
335
336 struct LocalData {
338 Vector<float4> averaged_colors;
339 };
341 for ([[maybe_unused]] const int iteration : IndexRange(2)) {
342 node_mask.foreach_index(GrainSize(1), [&](const int i) {
343 LocalData &tls = all_tls.local();
344 const Span<int> verts = nodes[i].verts();
345
346 tls.vert_neighbors.resize(verts.size());
347 calc_vert_neighbors(faces, corner_verts, vert_to_face_map, {}, verts, tls.vert_neighbors);
348 const Span<Vector<int>> vert_neighbors = tls.vert_neighbors;
349
350 tls.averaged_colors.resize(verts.size());
351 const MutableSpan<float4> averaged_colors = tls.averaged_colors;
353 pre_smoothed_color.as_span(), vert_neighbors, averaged_colors);
354
355 for (const int i : verts.index_range()) {
356 pre_smoothed_color[verts[i]] = math::interpolate(
357 pre_smoothed_color[verts[i]], averaged_colors[i], 0.5f);
358 }
359 });
360 }
361}
362
364{
365 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
366 SculptSession &ss = *ob.sculpt;
369
370 const FilterType mode = FilterType(RNA_enum_get(op->ptr, "type"));
371 float filter_strength = RNA_float_get(op->ptr, "strength");
372 float fill_color[3];
373
374 RNA_float_get_array(op->ptr, "fill_color", fill_color);
375 IMB_colormanagement_srgb_to_scene_linear_v3(fill_color, fill_color);
376
377 Mesh &mesh = *static_cast<Mesh *>(ob.data);
378 if (filter_strength < 0.0 && ss.filter_cache->pre_smoothed_color.is_empty()) {
380 }
381
382 const IndexMask &node_mask = ss.filter_cache->node_mask;
383
384 const OffsetIndices<int> faces = mesh.faces();
385 const Span<int> corner_verts = mesh.corner_verts();
386 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
388 const MeshAttributeData attribute_data(mesh.attributes());
389
391 node_mask.foreach_index(GrainSize(1), [&](const int i) {
392 LocalData &tls = all_tls.local();
394 ob,
395 faces,
396 corner_verts,
397 vert_to_face_map,
398 attribute_data,
399 mode,
400 filter_strength,
401 fill_color,
402 nodes[i],
403 tls,
404 color_attribute);
405 });
406 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
407 color_attribute.finish();
409}
410
412{
413 SculptSession &ss = *ob.sculpt;
414
415 undo::push_end(ob);
416 MEM_delete(ss.filter_cache);
417 ss.filter_cache = nullptr;
419}
420
421static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
422{
424 SculptSession &ss = *ob.sculpt;
425
426 if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
428 return OPERATOR_FINISHED;
429 }
430
431 if (event->type != MOUSEMOVE) {
433 }
434
435 const float len = (event->prev_press_xy[0] - event->xy[0]) * 0.001f;
436 float filter_strength = ss.filter_cache->start_filter_strength * -len;
437 RNA_float_set(op->ptr, "strength", filter_strength);
438
439 sculpt_color_filter_apply(C, op, ob);
440
442}
443
445{
446 const Scene &scene = *CTX_data_scene(C);
448 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
449 SculptSession &ss = *ob.sculpt;
450 View3D *v3d = CTX_wm_view3d(C);
451
452 const Base *base = CTX_data_active_base(C);
453 if (!BKE_base_is_visible(v3d, base)) {
454 return OPERATOR_CANCELLED;
455 }
456
457 int mval[2];
458 RNA_int_get_array(op->ptr, "start_mouse", mval);
459 float mval_fl[2] = {float(mval[0]), float(mval[1])};
460
461 const bool use_automasking = auto_mask::is_enabled(sd, ob, nullptr);
462 if (use_automasking) {
463 if (v3d) {
464 /* Update the active face set manually as the paint cursor is not enabled when using the Mesh
465 * Filter Tool. */
467 SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
468 }
469 }
470
471 /* Disable for multires and dyntopo for now */
473 return OPERATOR_CANCELLED;
474 }
475
476 undo::push_begin(scene, ob, op);
478
479 /* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
480 * earlier steps modifying the data. */
483
485 ob,
486 sd,
488 mval_fl,
489 RNA_float_get(op->ptr, "area_normal_radius"),
490 RNA_float_get(op->ptr, "strength"));
491 filter::Cache *filter_cache = ss.filter_cache;
493 filter_cache->automasking = auto_mask::cache_init(*depsgraph, sd, ob);
494
496}
497
499{
501
503 return OPERATOR_CANCELLED;
504 }
505
506 sculpt_color_filter_apply(C, op, ob);
508
509 return OPERATOR_FINISHED;
510}
511
512static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
513{
515 View3D *v3d = CTX_wm_view3d(C);
516 if (v3d && v3d->shading.type == OB_SOLID) {
518 }
519
520 RNA_int_set_array(op->ptr, "start_mouse", event->mval);
521
523 return OPERATOR_CANCELLED;
524 }
525
527
530}
531
533{
535 const int value = RNA_property_enum_get(ptr, prop);
536 const char *ui_name = nullptr;
537
538 RNA_property_enum_name_gettexted(nullptr, ptr, prop, value, &ui_name);
539 return ui_name;
540}
541
543{
544 uiLayout *layout = op->layout;
545
546 uiItemR(layout, op->ptr, "strength", UI_ITEM_NONE, nullptr, ICON_NONE);
547
548 if (FilterType(RNA_enum_get(op->ptr, "type")) == FilterType::Fill) {
549 uiItemR(layout, op->ptr, "fill_color", UI_ITEM_NONE, nullptr, ICON_NONE);
550 }
551}
552
554{
555 /* identifiers */
556 ot->name = "Filter Color";
557 ot->idname = "SCULPT_OT_color_filter";
558 ot->description = "Applies a filter to modify the active color attribute";
559
560 /* api callbacks */
567
569
570 /* rna */
572
574 ot->srna, "type", prop_color_filter_types, int(FilterType::Fill), "Filter Type", "");
575
577 "fill_color",
578 3,
580 0.0f,
581 FLT_MAX,
582 "Fill Color",
583 "",
584 0.0f,
585 1.0f);
588}
589
590} // namespace blender::ed::sculpt_paint::color
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
#define SCULPT_FACE_SET_NONE
Definition BKE_paint.hh:341
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
void BKE_sculpt_color_layer_create_if_needed(Object *object)
Definition paint.cc:2577
A BVH for high poly meshes.
#define BLI_NOINLINE
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
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_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:45
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)
#define BLT_I18NCONTEXT_ID_MESH
@ OB_SOLID
@ V3D_SHADING_VERTEX_COLOR
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_image_paint_brush_type_update_sticky_shading_color(bContext *C, 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.
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:175
#define UI_ITEM_NONE
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
@ KM_RELEASE
Definition WM_types.hh:285
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
void resize(const int64_t new_size)
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:593
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float2 fabs(const float2 a)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
std::unique_ptr< Cache > cache_init(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
bool is_enabled(const Sculpt &sd, const Object &object, const Brush *br)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
bke::GSpanAttributeWriter active_color_attribute_for_write(Mesh &mesh)
static std::string sculpt_color_filter_get_name(wmOperatorType *, PointerRNA *ptr)
static const float fill_filter_default_color[4]
static void color_filter_task(const Depsgraph &depsgraph, Object &ob, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const MeshAttributeData &attribute_data, const FilterType mode, const float filter_strength, const float *filter_fill_color, const bke::pbvh::MeshNode &node, LocalData &tls, bke::GSpanAttributeWriter &color_attribute)
static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static BLI_NOINLINE void clamp_factors(const MutableSpan< float > factors, const float min, const float max)
float4 color_vert_get(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, GSpan color_attribute, bke::AttrDomain color_domain, int vert)
void color_vert_set(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, bke::AttrDomain color_domain, int vert, const float4 &color, GMutableSpan color_attribute)
static int sculpt_color_filter_init(bContext *C, wmOperator *op)
void SCULPT_OT_color_filter(wmOperatorType *ot)
static int sculpt_color_filter_exec(bContext *C, wmOperator *op)
bke::GAttributeReader active_color_attribute(const Mesh &mesh)
static void sculpt_color_presmooth_init(const Mesh &mesh, Object &object)
static void sculpt_color_filter_end(bContext *C, Object &ob)
static void sculpt_color_filter_apply(bContext *C, wmOperator *op, Object &ob)
static void sculpt_color_filter_ui(bContext *, wmOperator *op)
static EnumPropertyItem prop_color_filter_types[]
static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
static BLI_NOINLINE void fill_factor_from_hide_and_mask(const Mesh &mesh, const Span< int > face_indices, const MutableSpan< float > r_factors)
void cache_init(bContext *C, Object &ob, const Sculpt &sd, undo::Type undo_type, const float mval_fl[2], float area_normal_radius, float start_strength)
void register_operator_props(wmOperatorType *ot)
void neighbor_color_average(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const GSpan color_attribute, const bke::AttrDomain color_domain, const Span< Vector< int > > vert_neighbors, const MutableSpan< float4 > smooth_colors)
void neighbor_data_average_mesh(const Span< T > src, const Span< Vector< int > > vert_neighbors, const MutableSpan< T > dst)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void flush_update_done(const bContext *C, Object &ob, UpdateType update_type)
Definition sculpt.cc:5055
void flush_update_step(bContext *C, UpdateType update_type)
Definition sculpt.cc:4960
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7227
Span< float4 > orig_color_data_get_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, MutableSpan< Vector< int > > result)
Definition sculpt.cc:7330
T clamp(const T &a, const T &min, const T &max)
T interpolate(const T &a, const T &b, const FactorT &t)
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
bool RNA_property_enum_name_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_name)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_color(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
Definition sculpt.cc:4580
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3560
bool SCULPT_handles_colors_report(const Object &object, ReportList *reports)
Definition sculpt.cc:5177
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
struct SculptSession * sculpt
blender::ed::sculpt_paint::filter::Cache * filter_cache
Definition BKE_paint.hh:428
View3DShading shading
std::unique_ptr< auto_mask::Cache > automasking
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
std::string(* get_name)(wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1068
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
void(* ui)(bContext *C, wmOperator *op)
Definition WM_types.hh:1053
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct uiLayout * layout
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ MOUSEMOVE
@ LEFTMOUSE
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125