Blender V4.3
sculpt_paint_image.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5/* Paint a color made from hash of node pointer. */
6// #define DEBUG_PIXEL_NODES
7
8#include "DNA_brush_types.h"
9#include "DNA_image_types.h"
10#include "DNA_object_types.h"
11
12#include "ED_paint.hh"
13
14#include "BLI_bit_vector.hh"
16#include "BLI_math_geom.h"
17#ifdef DEBUG_PIXEL_NODES
18# include "BLI_hash.h"
19#endif
20
22#include "IMB_imbuf.hh"
23
24#include "BKE_brush.hh"
25#include "BKE_image_wrappers.hh"
26#include "BKE_pbvh_api.hh"
27#include "BKE_pbvh_pixels.hh"
28
29#include "bmesh.hh"
30
31#include "mesh_brush_common.hh"
32#include "sculpt_automask.hh"
33#include "sculpt_intern.hh"
34
36
37using namespace blender::bke::pbvh::pixels;
38using namespace blender::bke::image;
39
40struct ImageData {
41 Image *image = nullptr;
43
44 ~ImageData() = default;
45
46 static bool init_active_image(Object &ob,
47 ImageData *r_image_data,
48 PaintModeSettings &paint_mode_settings)
49 {
51 &paint_mode_settings, &ob, &r_image_data->image, &r_image_data->image_user);
52 }
53};
54
57 private:
58 int pixel_offset;
59
60 public:
61 void set_image_position(ImBuf *image_buffer, ushort2 image_pixel_position)
62 {
63 pixel_offset = int(image_pixel_position.y) * image_buffer->x + int(image_pixel_position.x);
64 }
65
67 {
68 pixel_offset += 1;
69 }
70
71 float4 read_pixel(ImBuf *image_buffer) const
72 {
73 return &image_buffer->float_buffer.data[pixel_offset * 4];
74 }
75
76 void write_pixel(ImBuf *image_buffer, const float4 pixel_data) const
77 {
78 copy_v4_v4(&image_buffer->float_buffer.data[pixel_offset * 4], pixel_data);
79 }
80
81 const char *get_colorspace_name(ImBuf *image_buffer)
82 {
84 }
85};
86
89 private:
90 int pixel_offset;
91
92 public:
93 void set_image_position(ImBuf *image_buffer, ushort2 image_pixel_position)
94 {
95 pixel_offset = int(image_pixel_position.y) * image_buffer->x + int(image_pixel_position.x);
96 }
97
99 {
100 pixel_offset += 1;
101 }
102
103 float4 read_pixel(ImBuf *image_buffer) const
104 {
106 rgba_uchar_to_float(result,
107 static_cast<const uchar *>(static_cast<const void *>(
108 &(image_buffer->byte_buffer.data[4 * pixel_offset]))));
109 return result;
110 }
111
112 void write_pixel(ImBuf *image_buffer, const float4 pixel_data) const
113 {
114 rgba_float_to_uchar(static_cast<uchar *>(static_cast<void *>(
115 &image_buffer->byte_buffer.data[4 * pixel_offset])),
116 pixel_data);
117 }
118
119 const char *get_colorspace_name(ImBuf *image_buffer)
120 {
121 return IMB_colormanagement_get_rect_colorspace(image_buffer);
122 }
123};
124
125static float3 calc_pixel_position(const Span<float3> vert_positions,
126 const Span<int3> vert_tris,
127 const int tri_index,
128 const float2 &barycentric_weight)
129{
130 const int3 &verts = vert_tris[tri_index];
131 const float3 weights(barycentric_weight.x,
132 barycentric_weight.y,
133 1.0f - barycentric_weight.x - barycentric_weight.y);
135 interp_v3_v3v3v3(result,
136 vert_positions[verts[0]],
137 vert_positions[verts[1]],
138 vert_positions[verts[2]],
139 weights);
140 return result;
141}
142
143static void calc_pixel_row_positions(const Span<float3> vert_positions,
144 const Span<int3> vert_tris,
145 const Span<UVPrimitivePaintInput> uv_primitives,
146 const PackedPixelRow &pixel_row,
147 const MutableSpan<float3> positions)
148{
149 const float3 start = calc_pixel_position(vert_positions,
150 vert_tris,
151 uv_primitives[pixel_row.uv_primitive_index].tri_index,
152 pixel_row.start_barycentric_coord);
154 vert_positions,
155 vert_tris,
156 uv_primitives[pixel_row.uv_primitive_index].tri_index,
157 pixel_row.start_barycentric_coord +
158 uv_primitives[pixel_row.uv_primitive_index].delta_barycentric_coord_u);
159 const float3 delta = next - start;
160 for (const int i : IndexRange(pixel_row.num_pixels)) {
161 positions[i] = start + delta * i;
162 }
163}
164
165template<typename ImageBuffer> class PaintingKernel {
166 ImageBuffer image_accessor_;
167
168 float4 brush_color_;
169
170 const char *last_used_color_space_ = nullptr;
171
172 public:
173 explicit PaintingKernel() {}
174
175 bool paint(const Brush &brush,
176 const PackedPixelRow &pixel_row,
177 const Span<float> factors,
178 ImBuf *image_buffer)
179 {
180 image_accessor_.set_image_position(image_buffer, pixel_row.start_image_coordinate);
181 bool pixels_painted = false;
182 for (int x = 0; x < pixel_row.num_pixels; x++) {
183 float4 color = image_accessor_.read_pixel(image_buffer);
184 float4 paint_color = brush_color_ * factors[x];
185 float4 buffer_color;
186
187#ifdef DEBUG_PIXEL_NODES
188 if ((pixel_row.start_image_coordinate.y >> 3) & 1) {
189 paint_color[0] *= 0.5f;
190 paint_color[1] *= 0.5f;
191 paint_color[2] *= 0.5f;
192 }
193#endif
194
195 blend_color_mix_float(buffer_color, color, paint_color);
196 buffer_color *= brush.alpha;
197 IMB_blend_color_float(color, color, buffer_color, static_cast<IMB_BlendMode>(brush.blend));
198 image_accessor_.write_pixel(image_buffer, color);
199 pixels_painted = true;
200
201 image_accessor_.next_pixel();
202 }
203 return pixels_painted;
204 }
205
206 void init_brush_color(ImBuf *image_buffer, float in_brush_color[3])
207 {
208 const char *to_colorspace = image_accessor_.get_colorspace_name(image_buffer);
209 if (last_used_color_space_ == to_colorspace) {
210 return;
211 }
212
213 /* NOTE: Brush colors are stored in sRGB. We use math color to follow other areas that
214 * use brush colors. From there on we use IMB_colormanagement to convert the brush color to the
215 * colorspace of the texture. This isn't ideal, but would need more refactoring to make sure
216 * that brush colors are stored in scene linear by default. */
217 srgb_to_linearrgb_v3_v3(brush_color_, in_brush_color);
218 brush_color_[3] = 1.0f;
219
220 const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
223 from_colorspace, to_colorspace);
224 IMB_colormanagement_processor_apply_v4(cm_processor, brush_color_);
226 last_used_color_space_ = to_colorspace;
227 }
228};
229
231 const Span<int3> vert_tris,
232 const Span<UVPrimitivePaintInput> uv_primitives,
233 const Span<float3> positions)
234{
235 const float3 location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
236 const float radius = ss.cache ? ss.cache->radius : ss.cursor_radius;
237 const Bounds<float3> brush_bounds(location - radius, location + radius);
238
239 BitVector<> brush_test(uv_primitives.size());
240 for (const int i : uv_primitives.index_range()) {
241 const UVPrimitivePaintInput &paint_input = uv_primitives[i];
242 const int3 verts = vert_tris[paint_input.tri_index];
243
244 Bounds<float3> tri_bounds(positions[verts[0]]);
245 math::min_max(positions[verts[1]], tri_bounds.min, tri_bounds.max);
246 math::min_max(positions[verts[2]], tri_bounds.min, tri_bounds.max);
247
248 brush_test[i].set(
249 isect_aabb_aabb_v3(brush_bounds.min, brush_bounds.max, tri_bounds.min, tri_bounds.max));
250 }
251 return brush_test;
252}
253
254static void do_paint_pixels(const Scene &scene,
255 const Depsgraph &depsgraph,
256 Object &object,
257 const Paint &paint,
258 const Brush &brush,
259 ImageData image_data,
260 bke::pbvh::Node &node)
261{
262 SculptSession &ss = *object.sculpt;
263 const StrokeCache &cache = *ss.cache;
264 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
265 PBVHData &pbvh_data = bke::pbvh::pixels::data_get(pbvh);
267 const Span<float3> positions = bke::pbvh::vert_positions_eval(depsgraph, object);
268
270 ss, pbvh_data.vert_tris, node_data.uv_primitives, positions);
271
274
275 float4 brush_color;
276
277#ifdef DEBUG_PIXEL_NODES
279
280 brush_color[0] = float(hash & 255) / 255.0f;
281 brush_color[1] = float((hash >> 8) & 255) / 255.0f;
282 brush_color[2] = float((hash >> 16) & 255) / 255.0f;
283#else
284 copy_v3_v3(brush_color,
285 ss.cache->invert ? BKE_brush_secondary_color_get(&scene, &paint, &brush) :
286 BKE_brush_color_get(&scene, &paint, &brush));
287#endif
288
289 brush_color[3] = 1.0f;
290
291 Vector<float3> pixel_positions;
292 Vector<float> factors;
293 Vector<float> distances;
294
295 ImageUser image_user = *image_data.image_user;
296 bool pixels_updated = false;
297 for (UDIMTilePixels &tile_data : node_data.tiles) {
298 LISTBASE_FOREACH (ImageTile *, tile, &image_data.image->tiles) {
299 ImageTileWrapper image_tile(tile);
300 if (image_tile.get_tile_number() == tile_data.tile_number) {
301 image_user.tile = image_tile.get_tile_number();
302
303 ImBuf *image_buffer = BKE_image_acquire_ibuf(image_data.image, &image_user, nullptr);
304 if (image_buffer == nullptr) {
305 continue;
306 }
307
308 if (image_buffer->float_buffer.data != nullptr) {
309 kernel_float4.init_brush_color(image_buffer, brush_color);
310 }
311 else {
312 kernel_byte4.init_brush_color(image_buffer, brush_color);
313 }
314
315 for (const PackedPixelRow &pixel_row : tile_data.pixel_rows) {
316 if (!brush_test[pixel_row.uv_primitive_index]) {
317 continue;
318 }
319
320 pixel_positions.resize(pixel_row.num_pixels);
322 positions, pbvh_data.vert_tris, node_data.uv_primitives, pixel_row, pixel_positions);
323
324 factors.resize(pixel_positions.size());
325 factors.fill(1.0f);
326
327 distances.resize(pixel_positions.size());
329 ss, pixel_positions, eBrushFalloffShape(brush.falloff_shape), distances);
330 filter_distances_with_radius(cache.radius, distances, factors);
331 apply_hardness_to_distances(cache, distances);
332 calc_brush_strength_factors(cache, brush, distances, factors);
333 calc_brush_texture_factors(ss, brush, pixel_positions, factors);
334 scale_factors(factors, cache.bstrength);
335
336 bool pixels_painted = false;
337 if (image_buffer->float_buffer.data != nullptr) {
338 pixels_painted = kernel_float4.paint(brush, pixel_row, factors, image_buffer);
339 }
340 else {
341 pixels_painted = kernel_byte4.paint(brush, pixel_row, factors, image_buffer);
342 }
343
344 if (pixels_painted) {
345 tile_data.mark_dirty(pixel_row);
346 }
347 }
348
349 BKE_image_release_ibuf(image_data.image, image_buffer, nullptr);
350 pixels_updated |= tile_data.flags.dirty;
351 break;
352 }
353 }
354 }
355
356 node_data.flags.dirty |= pixels_updated;
357}
358
360 ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
361{
362 int srcx = 0, srcy = 0;
363 IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
364 *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
365 *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
366 *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
367 *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
368}
369
370static void push_undo(const NodeData &node_data,
371 Image &image,
372 ImageUser &image_user,
373 const image::ImageTileWrapper &image_tile,
374 ImBuf &image_buffer,
375 ImBuf **tmpibuf)
376{
377 for (const UDIMTileUndo &tile_undo : node_data.undo_regions) {
378 if (tile_undo.tile_number != image_tile.get_tile_number()) {
379 continue;
380 }
381 int tilex, tiley, tilew, tileh;
383 undo_region_tiles(&image_buffer,
384 tile_undo.region.xmin,
385 tile_undo.region.ymin,
386 BLI_rcti_size_x(&tile_undo.region),
387 BLI_rcti_size_y(&tile_undo.region),
388 &tilex,
389 &tiley,
390 &tilew,
391 &tileh);
392 for (int ty = tiley; ty <= tileh; ty++) {
393 for (int tx = tilex; tx <= tilew; tx++) {
394 ED_image_paint_tile_push(undo_tiles,
395 &image,
396 &image_buffer,
397 tmpibuf,
398 &image_user,
399 tx,
400 ty,
401 nullptr,
402 nullptr,
403 true,
404 true);
405 }
406 }
407 }
408}
409
410static void do_push_undo_tile(Image &image, ImageUser &image_user, bke::pbvh::Node &node)
411{
413
414 ImBuf *tmpibuf = nullptr;
415 ImageUser local_image_user = image_user;
416 LISTBASE_FOREACH (ImageTile *, tile, &image.tiles) {
417 image::ImageTileWrapper image_tile(tile);
418 local_image_user.tile = image_tile.get_tile_number();
419 ImBuf *image_buffer = BKE_image_acquire_ibuf(&image, &local_image_user, nullptr);
420 if (image_buffer == nullptr) {
421 continue;
422 }
423
424 push_undo(node_data, image, image_user, image_tile, *image_buffer, &tmpibuf);
425 BKE_image_release_ibuf(&image, image_buffer, nullptr);
426 }
427 if (tmpibuf) {
428 IMB_freeImBuf(tmpibuf);
429 }
430}
431
432/* -------------------------------------------------------------------- */
433
438 const IndexMask &node_mask)
439{
440 Vector<image::TileNumber> dirty_tiles;
441 node_mask.foreach_index(
442 [&](const int i) { bke::pbvh::pixels::collect_dirty_tiles(nodes[i], dirty_tiles); });
443 return dirty_tiles;
444}
446 Image &image,
447 ImageUser &image_user,
448 Span<TileNumber> tile_numbers_to_fix)
449{
450 for (image::TileNumber tile_number : tile_numbers_to_fix) {
451 bke::pbvh::pixels::copy_pixels(pbvh, image, image_user, tile_number);
452 }
453}
454
456 Image &image,
457 ImageUser &image_user,
459 const IndexMask &node_mask)
460{
461 Vector<image::TileNumber> dirty_tiles = collect_dirty_tiles(nodes, node_mask);
462 fix_non_manifold_seam_bleeding(*bke::object::pbvh_get(ob), image, image_user, dirty_tiles);
463}
464
467} // namespace blender::ed::sculpt_paint::paint::image
468
470
472 Object &ob,
473 Image **r_image,
474 ImageUser **r_image_user)
475{
476 *r_image = nullptr;
477 *r_image_user = nullptr;
478
479 ImageData image_data;
480 if (!ImageData::init_active_image(ob, &image_data, paint_mode_settings)) {
481 return false;
482 }
483
484 *r_image = image_data.image;
485 *r_image_user = image_data.image_user;
486 return true;
487}
488
490{
491 if (!U.experimental.use_sculpt_texture_paint) {
492 return false;
493 }
494 if (ob.type != OB_MESH) {
495 return false;
496 }
497 Image *image;
498 ImageUser *image_user;
499 return BKE_paint_canvas_image_get(&settings, &ob, &image, &image_user);
500}
501
503 const Depsgraph &depsgraph,
504 PaintModeSettings &paint_mode_settings,
505 const Sculpt &sd,
506 Object &ob,
507 const blender::IndexMask &node_mask)
508{
509 using namespace blender;
510 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
511
512 ImageData image_data;
513 if (!ImageData::init_active_image(ob, &image_data, paint_mode_settings)) {
514 return;
515 }
516
517 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
519
520 node_mask.foreach_index(GrainSize(1), [&](const int i) {
521 do_push_undo_tile(*image_data.image, *image_data.image_user, nodes[i]);
522 });
523 node_mask.foreach_index(GrainSize(1), [&](const int i) {
524 do_paint_pixels(scene, depsgraph, ob, sd.paint, *brush, image_data, nodes[i]);
525 });
526
527 fix_non_manifold_seam_bleeding(ob, *image_data.image, *image_data.image_user, nodes, node_mask);
528
529 node_mask.foreach_index([&](const int i) {
530 bke::pbvh::pixels::mark_image_dirty(nodes[i], *image_data.image, *image_data.image_user);
531 });
532}
const float * BKE_brush_secondary_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1037
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1029
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
bool BKE_paint_canvas_image_get(PaintModeSettings *settings, Object *ob, Image **r_image, ImageUser **r_image_user)
A BVH for high poly meshes.
BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
Definition BLI_hash.h:91
#define LISTBASE_FOREACH(type, var, list)
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
unsigned char uchar
unsigned int uint
#define POINTER_AS_UINT(i)
eBrushFalloffShape
Object is a sort of wrapper for general info.
@ OB_MESH
void * ED_image_paint_tile_push(PaintTileMap *paint_tile_map, Image *image, ImBuf *ibuf, ImBuf **tmpibuf, ImageUser *iuser, int x_tile, int y_tile, unsigned short **r_mask, bool **r_valid, bool use_thread_lock, bool find_prev)
PaintTileMap * ED_image_paint_tile_map_get()
#define ED_IMAGE_UNDO_TILE_BITS
Definition ED_paint.hh:106
ColormanageProcessor * IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace)
const char * IMB_colormanagement_role_colorspace_name_get(int role)
@ COLOR_ROLE_SCENE_LINEAR
void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
const char * IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor, float pixel[4])
const char * IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
void IMB_rectclip(ImBuf *dbuf, const ImBuf *sbuf, int *destx, int *desty, int *srcx, int *srcy, int *width, int *height)
Definition rectop.cc:306
IMB_BlendMode
Definition IMB_imbuf.hh:186
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition rectop.cc:115
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
int64_t size() const
void resize(const int64_t new_size)
void fill(const T &value) const
Span< NodeT > nodes() const
void write_pixel(ImBuf *image_buffer, const float4 pixel_data) const
void set_image_position(ImBuf *image_buffer, ushort2 image_pixel_position)
void set_image_position(ImBuf *image_buffer, ushort2 image_pixel_position)
void write_pixel(ImBuf *image_buffer, const float4 pixel_data) const
bool paint(const Brush &brush, const PackedPixelRow &pixel_row, const Span< float > factors, ImBuf *image_buffer)
void init_brush_color(ImBuf *image_buffer, float in_brush_color[3])
void foreach_index(Fn &&fn) const
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
const Depsgraph * depsgraph
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]
void IMB_freeImBuf(ImBuf *)
ccl_global const KernelWorkTile * tile
static ulong * next
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
NodeData & node_data_get(blender::bke::pbvh::Node &node)
void copy_pixels(blender::bke::pbvh::Tree &pbvh, Image &image, ImageUser &image_user, image::TileNumber tile_number)
void collect_dirty_tiles(blender::bke::pbvh::Node &node, Vector< image::TileNumber > &r_dirty_tiles)
PBVHData & data_get(blender::bke::pbvh::Tree &pbvh)
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
static void fix_non_manifold_seam_bleeding(bke::pbvh::Tree &pbvh, Image &image, ImageUser &image_user, Span< TileNumber > tile_numbers_to_fix)
static float3 calc_pixel_position(const Span< float3 > vert_positions, const Span< int3 > vert_tris, const int tri_index, const float2 &barycentric_weight)
static void do_paint_pixels(const Scene &scene, const Depsgraph &depsgraph, Object &object, const Paint &paint, const Brush &brush, ImageData image_data, bke::pbvh::Node &node)
static BitVector init_uv_primitives_brush_test(SculptSession &ss, const Span< int3 > vert_tris, const Span< UVPrimitivePaintInput > uv_primitives, const Span< float3 > positions)
static void calc_pixel_row_positions(const Span< float3 > vert_positions, const Span< int3 > vert_tris, const Span< UVPrimitivePaintInput > uv_primitives, const PackedPixelRow &pixel_row, const MutableSpan< float3 > positions)
static void push_undo(const NodeData &node_data, Image &image, ImageUser &image_user, const image::ImageTileWrapper &image_tile, ImBuf &image_buffer, ImBuf **tmpibuf)
static void undo_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
static void do_push_undo_tile(Image &image, ImageUser &image_user, bke::pbvh::Node &node)
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6889
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:6862
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6772
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert_indices, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:6722
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7227
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert_indices, MutableSpan< float > factors)
Definition sculpt.cc:6898
void min_max(const T &value, T &min, T &max)
#define hash
Definition noise.c:154
bool SCULPT_paint_image_canvas_get(PaintModeSettings &paint_mode_settings, Object &ob, Image **r_image, ImageUser **r_image_user)
Get the image canvas for painting on the given object.
void SCULPT_do_paint_brush_image(const Scene &scene, const Depsgraph &depsgraph, PaintModeSettings &paint_mode_settings, const Sculpt &sd, Object &ob, const blender::IndexMask &node_mask)
bool SCULPT_use_image_paint_brush(PaintModeSettings &settings, Object &ob)
float alpha
char falloff_shape
short blend
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ListBase tiles
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
float cursor_radius
Definition BKE_paint.hh:439
blender::float3 cursor_location
Definition BKE_paint.hh:440
struct blender::bke::pbvh::pixels::NodeData::@53 flags
Vector< UVPrimitivePaintInput > uv_primitives
static bool init_active_image(Object &ob, ImageData *r_image_data, PaintModeSettings &paint_mode_settings)