Blender V5.0
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#include "DNA_userdef_types.h"
12
13#include "ED_paint.hh"
14
15#include "BLI_bit_vector.hh"
16#include "BLI_listbase.h"
18#include "BLI_math_geom.h"
19#ifdef DEBUG_PIXEL_NODES
20# include "BLI_hash.h"
21#endif
22
24#include "IMB_imbuf.hh"
25
26#include "BKE_brush.hh"
27#include "BKE_image_wrappers.hh"
28#include "BKE_paint_bvh.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 {
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);
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() = default;
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 copy_v3_v3(brush_color_, in_brush_color);
214 brush_color_[3] = 1.0f;
215
216 const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
219 from_colorspace, to_colorspace);
220 IMB_colormanagement_processor_apply_v4(cm_processor, brush_color_);
222 last_used_color_space_ = to_colorspace;
223 }
224};
225
227 const Span<int3> vert_tris,
228 const Span<UVPrimitivePaintInput> uv_primitives,
229 const Span<float3> positions)
230{
231 const float3 location = ss.cache ? ss.cache->location_symm : ss.cursor_location;
232 const float radius = ss.cache ? ss.cache->radius : ss.cursor_radius;
233 const Bounds<float3> brush_bounds(location - radius, location + radius);
234
235 BitVector<> brush_test(uv_primitives.size());
236 for (const int i : uv_primitives.index_range()) {
237 const UVPrimitivePaintInput &paint_input = uv_primitives[i];
238 const int3 verts = vert_tris[paint_input.tri_index];
239
240 Bounds<float3> tri_bounds(positions[verts[0]]);
241 math::min_max(positions[verts[1]], tri_bounds.min, tri_bounds.max);
242 math::min_max(positions[verts[2]], tri_bounds.min, tri_bounds.max);
243
244 brush_test[i].set(
245 isect_aabb_aabb_v3(brush_bounds.min, brush_bounds.max, tri_bounds.min, tri_bounds.max));
246 }
247 return brush_test;
248}
249
250static void do_paint_pixels(const Depsgraph &depsgraph,
251 Object &object,
252 const Paint &paint,
253 const Brush &brush,
254 ImageData image_data,
255 bke::pbvh::Node &node)
256{
257 SculptSession &ss = *object.sculpt;
258 const StrokeCache &cache = *ss.cache;
262 const Span<float3> positions = bke::pbvh::vert_positions_eval(depsgraph, object);
263
265 ss, pbvh_data.vert_tris, node_data.uv_primitives, positions);
266
269
270 float4 brush_color;
271
272#ifdef DEBUG_PIXEL_NODES
274
275 brush_color[0] = float(hash & 255) / 255.0f;
276 brush_color[1] = float((hash >> 8) & 255) / 255.0f;
277 brush_color[2] = float((hash >> 16) & 255) / 255.0f;
278#else
279 copy_v3_v3(brush_color,
282#endif
283
284 brush_color[3] = 1.0f;
285
286 Vector<float3> pixel_positions;
287 Vector<float> factors;
288 Vector<float> distances;
289
290 ImageUser image_user = *image_data.image_user;
291 bool pixels_updated = false;
292 for (UDIMTilePixels &tile_data : node_data.tiles) {
293 LISTBASE_FOREACH (ImageTile *, tile, &image_data.image->tiles) {
294 ImageTileWrapper image_tile(tile);
295 if (image_tile.get_tile_number() == tile_data.tile_number) {
296 image_user.tile = image_tile.get_tile_number();
297
298 ImBuf *image_buffer = BKE_image_acquire_ibuf(image_data.image, &image_user, nullptr);
299 if (image_buffer == nullptr) {
300 continue;
301 }
302
303 if (image_buffer->float_buffer.data != nullptr) {
304 kernel_float4.init_brush_color(image_buffer, brush_color);
305 }
306 else {
307 kernel_byte4.init_brush_color(image_buffer, brush_color);
308 }
309
310 for (const PackedPixelRow &pixel_row : tile_data.pixel_rows) {
311 if (!brush_test[pixel_row.uv_primitive_index]) {
312 continue;
313 }
314
315 pixel_positions.resize(pixel_row.num_pixels);
317 positions, pbvh_data.vert_tris, node_data.uv_primitives, pixel_row, pixel_positions);
318
319 factors.resize(pixel_positions.size());
320 factors.fill(1.0f);
321
322 distances.resize(pixel_positions.size());
324 ss, pixel_positions, eBrushFalloffShape(brush.falloff_shape), distances);
325 filter_distances_with_radius(cache.radius, distances, factors);
326 apply_hardness_to_distances(cache, distances);
327 calc_brush_strength_factors(cache, brush, distances, factors);
328 calc_brush_texture_factors(ss, brush, pixel_positions, factors);
329 scale_factors(factors, cache.bstrength);
330
331 bool pixels_painted = false;
332 if (image_buffer->float_buffer.data != nullptr) {
333 pixels_painted = kernel_float4.paint(brush, pixel_row, factors, image_buffer);
334 }
335 else {
336 pixels_painted = kernel_byte4.paint(brush, pixel_row, factors, image_buffer);
337 }
338
339 if (pixels_painted) {
340 tile_data.mark_dirty(pixel_row);
341 }
342 }
343
344 BKE_image_release_ibuf(image_data.image, image_buffer, nullptr);
345 pixels_updated |= tile_data.flags.dirty;
346 break;
347 }
348 }
349 }
350
351 node_data.flags.dirty |= pixels_updated;
352}
353
355 ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
356{
357 int srcx = 0, srcy = 0;
358 IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
359 *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
360 *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
361 *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
362 *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
363}
364
365static void push_undo(const NodeData &node_data,
366 Image &image,
367 ImageUser &image_user,
368 const image::ImageTileWrapper &image_tile,
369 ImBuf &image_buffer,
370 ImBuf **tmpibuf)
371{
372 for (const UDIMTileUndo &tile_undo : node_data.undo_regions) {
373 if (tile_undo.tile_number != image_tile.get_tile_number()) {
374 continue;
375 }
376 int tilex, tiley, tilew, tileh;
378 undo_region_tiles(&image_buffer,
379 tile_undo.region.xmin,
380 tile_undo.region.ymin,
381 BLI_rcti_size_x(&tile_undo.region),
382 BLI_rcti_size_y(&tile_undo.region),
383 &tilex,
384 &tiley,
385 &tilew,
386 &tileh);
387 for (int ty = tiley; ty <= tileh; ty++) {
388 for (int tx = tilex; tx <= tilew; tx++) {
389 ED_image_paint_tile_push(undo_tiles,
390 &image,
391 &image_buffer,
392 tmpibuf,
393 &image_user,
394 tx,
395 ty,
396 nullptr,
397 nullptr,
398 true,
399 true);
400 }
401 }
402 }
403}
404
405static void do_push_undo_tile(Image &image, ImageUser &image_user, bke::pbvh::Node &node)
406{
408
409 ImBuf *tmpibuf = nullptr;
410 ImageUser local_image_user = image_user;
411 LISTBASE_FOREACH (ImageTile *, tile, &image.tiles) {
412 image::ImageTileWrapper image_tile(tile);
413 local_image_user.tile = image_tile.get_tile_number();
414 ImBuf *image_buffer = BKE_image_acquire_ibuf(&image, &local_image_user, nullptr);
415 if (image_buffer == nullptr) {
416 continue;
417 }
418
419 push_undo(node_data, image, image_user, image_tile, *image_buffer, &tmpibuf);
420 BKE_image_release_ibuf(&image, image_buffer, nullptr);
421 }
422 if (tmpibuf) {
423 IMB_freeImBuf(tmpibuf);
424 }
425}
426
427/* -------------------------------------------------------------------- */
428
431
433 const IndexMask &node_mask)
434{
435 Vector<image::TileNumber> dirty_tiles;
436 node_mask.foreach_index(
437 [&](const int i) { bke::pbvh::pixels::collect_dirty_tiles(nodes[i], dirty_tiles); });
438 return dirty_tiles;
439}
441 Image &image,
442 ImageUser &image_user,
443 Span<TileNumber> tile_numbers_to_fix)
444{
445 for (image::TileNumber tile_number : tile_numbers_to_fix) {
446 bke::pbvh::pixels::copy_pixels(pbvh, image, image_user, tile_number);
447 }
448}
449
451 Image &image,
452 ImageUser &image_user,
454 const IndexMask &node_mask)
455{
456 Vector<image::TileNumber> dirty_tiles = collect_dirty_tiles(nodes, node_mask);
457 fix_non_manifold_seam_bleeding(*bke::object::pbvh_get(ob), image, image_user, dirty_tiles);
458}
459
461
462} // namespace blender::ed::sculpt_paint::paint::image
463
465
467 Object &ob,
468 Image **r_image,
469 ImageUser **r_image_user)
470{
471 *r_image = nullptr;
472 *r_image_user = nullptr;
473
474 ImageData image_data;
475 if (!ImageData::init_active_image(ob, &image_data, paint_mode_settings)) {
476 return false;
477 }
478
479 *r_image = image_data.image;
480 *r_image_user = image_data.image_user;
481 return true;
482}
483
485{
486 if (!USER_EXPERIMENTAL_TEST(&U, use_sculpt_texture_paint)) {
487 return false;
488 }
489 if (ob.type != OB_MESH) {
490 return false;
491 }
492 Image *image;
493 ImageUser *image_user;
494 return BKE_paint_canvas_image_get(&settings, &ob, &image, &image_user);
495}
496
498 PaintModeSettings &paint_mode_settings,
499 const Sculpt &sd,
500 Object &ob,
501 const blender::IndexMask &node_mask)
502{
503 using namespace blender;
505
506 ImageData image_data;
507 if (!ImageData::init_active_image(ob, &image_data, paint_mode_settings)) {
508 return;
509 }
510
513
514 node_mask.foreach_index(GrainSize(1), [&](const int i) {
515 do_push_undo_tile(*image_data.image, *image_data.image_user, nodes[i]);
516 });
517 node_mask.foreach_index(GrainSize(1), [&](const int i) {
518 do_paint_pixels(depsgraph, ob, sd.paint, *brush, image_data, nodes[i]);
519 });
520
521 fix_non_manifold_seam_bleeding(ob, *image_data.image, *image_data.image_user, nodes, node_mask);
522
523 node_mask.foreach_index([&](const int i) {
524 bke::pbvh::pixels::mark_image_dirty(nodes[i], *image_data.image, *image_data.image_user);
525 });
526}
const float * BKE_brush_color_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1161
const float * BKE_brush_secondary_color_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1205
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:650
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:87
#define LISTBASE_FOREACH(type, var, list)
MINLINE void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
MINLINE void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
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:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
unsigned char uchar
unsigned int uint
#define POINTER_AS_UINT(i)
eBrushFalloffShape
Object is a sort of wrapper for general info.
@ OB_MESH
#define USER_EXPERIMENTAL_TEST(userdef, member)
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:113
const char * IMB_colormanagement_get_rect_colorspace(const ImBuf *ibuf)
ColormanageProcessor * IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace)
@ COLOR_ROLE_SCENE_LINEAR
const char * IMB_colormanagement_role_colorspace_name_get(int role)
const char * IMB_colormanagement_get_float_colorspace(const ImBuf *ibuf)
void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor, float pixel[4])
void IMB_rectclip(ImBuf *dbuf, const ImBuf *sbuf, int *destx, int *desty, int *srcx, int *srcy, int *width, int *height)
Definition rectop.cc:307
IMB_BlendMode
Definition IMB_imbuf.hh:178
void IMB_freeImBuf(ImBuf *ibuf)
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition rectop.cc:116
#define U
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
void resize(const int64_t new_size)
void fill(const T &value) 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
nullptr float
static float verts[][3]
const ccl_global KernelWorkTile * tile
static ulong * next
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
NodeData & node_data_get(blender::bke::pbvh::Node &node)
void mark_image_dirty(blender::bke::pbvh::Node &node, Image &image, ImageUser &image_user)
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:1040
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 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 do_paint_pixels(const Depsgraph &depsgraph, Object &object, const Paint &paint, const Brush &brush, ImageData image_data, bke::pbvh::Node &node)
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:7183
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7105
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7055
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7195
void min_max(const T &value, T &min, T &max)
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< uint16_t, 2 > ushort2
VecBase< float, 3 > float3
#define hash
Definition noise_c.cc: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 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)
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
ListBase tiles
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
float cursor_radius
Definition BKE_paint.hh:429
blender::float3 cursor_location
Definition BKE_paint.hh:430
struct blender::bke::pbvh::pixels::NodeData::@126372137103364156366300331140353251345266233066 flags
Vector< UVPrimitivePaintInput > uv_primitives
void mark_dirty(const PackedPixelRow &pixel_row)
struct blender::bke::pbvh::pixels::UDIMTilePixels::@213142071117224155011332260101117126053322200307 flags
static bool init_active_image(Object &ob, ImageData *r_image_data, PaintModeSettings &paint_mode_settings)
int ymin
int xmin
i
Definition text_draw.cc:230