Blender  V3.3
sculpt_paint_image.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2022 Blender Foundation. All rights reserved. */
3 
4 #include "DNA_image_types.h"
5 #include "DNA_material_types.h"
6 #include "DNA_mesh_types.h"
7 #include "DNA_node_types.h"
8 #include "DNA_object_types.h"
9 
10 #include "ED_paint.h"
11 #include "ED_uvedit.h"
12 
13 #include "BLI_math.h"
14 #include "BLI_math_color_blend.h"
15 #include "BLI_task.h"
16 
17 #include "IMB_colormanagement.h"
18 #include "IMB_imbuf.h"
19 
20 #include "BKE_brush.h"
21 #include "BKE_image_wrappers.hh"
22 #include "BKE_material.h"
23 #include "BKE_pbvh.h"
24 #include "BKE_pbvh_pixels.hh"
25 
26 #include "bmesh.h"
27 
28 #include "NOD_shader.h"
29 
30 #include "sculpt_intern.h"
31 
33 
34 using namespace blender::bke::pbvh::pixels;
35 using namespace blender::bke::image;
36 
37 struct ImageData {
38  Image *image = nullptr;
39  ImageUser *image_user = nullptr;
40 
41  ~ImageData() = default;
42 
43  static bool init_active_image(Object *ob,
44  ImageData *r_image_data,
45  PaintModeSettings *paint_mode_settings)
46  {
48  paint_mode_settings, ob, &r_image_data->image, &r_image_data->image_user);
49  }
50 };
51 
57 };
58 
61  private:
62  int pixel_offset;
63 
64  public:
65  void set_image_position(ImBuf *image_buffer, ushort2 image_pixel_position)
66  {
67  pixel_offset = int(image_pixel_position.y) * image_buffer->x + int(image_pixel_position.x);
68  }
69 
70  void next_pixel()
71  {
72  pixel_offset += 1;
73  }
74 
75  float4 read_pixel(ImBuf *image_buffer) const
76  {
77  return &image_buffer->rect_float[pixel_offset * 4];
78  }
79 
80  void write_pixel(ImBuf *image_buffer, const float4 pixel_data) const
81  {
82  copy_v4_v4(&image_buffer->rect_float[pixel_offset * 4], pixel_data);
83  }
84 
85  const char *get_colorspace_name(ImBuf *image_buffer)
86  {
87  return IMB_colormanagement_get_float_colorspace(image_buffer);
88  }
89 };
90 
93  private:
94  int pixel_offset;
95 
96  public:
97  void set_image_position(ImBuf *image_buffer, ushort2 image_pixel_position)
98  {
99  pixel_offset = int(image_pixel_position.y) * image_buffer->x + int(image_pixel_position.x);
100  }
101 
102  void next_pixel()
103  {
104  pixel_offset += 1;
105  }
106 
107  float4 read_pixel(ImBuf *image_buffer) const
108  {
109  float4 result;
111  static_cast<const uchar *>(
112  static_cast<const void *>(&(image_buffer->rect[pixel_offset]))));
113  return result;
114  }
115 
116  void write_pixel(ImBuf *image_buffer, const float4 pixel_data) const
117  {
119  static_cast<uchar *>(static_cast<void *>(&image_buffer->rect[pixel_offset])), pixel_data);
120  }
121 
122  const char *get_colorspace_name(ImBuf *image_buffer)
123  {
124  return IMB_colormanagement_get_rect_colorspace(image_buffer);
125  }
126 };
127 
128 template<typename ImageBuffer> class PaintingKernel {
129  ImageBuffer image_accessor;
130 
131  SculptSession *ss;
132  const Brush *brush;
133  const int thread_id;
134  const MVert *mvert;
135 
136  float4 brush_color;
137  float brush_strength;
138 
139  SculptBrushTestFn brush_test_fn;
140  SculptBrushTest test;
141  /* Pointer to the last used image buffer to detect when buffers are switched. */
142  void *last_used_image_buffer_ptr = nullptr;
143  const char *last_used_color_space = nullptr;
144 
145  public:
147  const Brush *brush,
148  const int thread_id,
149  const MVert *mvert)
150  : ss(ss), brush(brush), thread_id(thread_id), mvert(mvert)
151  {
152  init_brush_strength();
153  init_brush_test();
154  }
155 
156  bool paint(const Triangles &triangles, const PackedPixelRow &pixel_row, ImBuf *image_buffer)
157  {
158  image_accessor.set_image_position(image_buffer, pixel_row.start_image_coordinate);
159  const TrianglePaintInput triangle = triangles.get_paint_input(pixel_row.triangle_index);
160  float3 pixel_pos = get_start_pixel_pos(triangle, pixel_row);
161  const float3 delta_pixel_pos = get_delta_pixel_pos(triangle, pixel_row, pixel_pos);
162  bool pixels_painted = false;
163  for (int x = 0; x < pixel_row.num_pixels; x++) {
164  if (!brush_test_fn(&test, pixel_pos)) {
165  pixel_pos += delta_pixel_pos;
166  image_accessor.next_pixel();
167  continue;
168  }
169 
170  float4 color = image_accessor.read_pixel(image_buffer);
171  const float3 normal(0.0f, 0.0f, 0.0f);
172  const float3 face_normal(0.0f, 0.0f, 0.0f);
173  const float mask = 0.0f;
174  const float falloff_strength = SCULPT_brush_strength_factor(
175  ss, brush, pixel_pos, sqrtf(test.dist), normal, face_normal, mask, 0, thread_id);
176  float4 paint_color = brush_color * falloff_strength * brush_strength;
177  float4 buffer_color;
178  blend_color_mix_float(buffer_color, color, paint_color);
179  buffer_color *= brush->alpha;
180  IMB_blend_color_float(color, color, buffer_color, static_cast<IMB_BlendMode>(brush->blend));
181  image_accessor.write_pixel(image_buffer, color);
182  pixels_painted = true;
183 
184  image_accessor.next_pixel();
185  pixel_pos += delta_pixel_pos;
186  }
187  return pixels_painted;
188  }
189 
190  void init_brush_color(ImBuf *image_buffer)
191  {
192  const char *to_colorspace = image_accessor.get_colorspace_name(image_buffer);
193  if (last_used_color_space == to_colorspace) {
194  return;
195  }
196  copy_v3_v3(brush_color,
197  ss->cache->invert ? BKE_brush_secondary_color_get(ss->scene, brush) :
198  BKE_brush_color_get(ss->scene, brush));
199  /* NOTE: Brush colors are stored in sRGB. We use math color to follow other areas that
200  * use brush colors. From there on we use IMB_colormanagement to convert the brush color to the
201  * colorspace of the texture. This isn't ideal, but would need more refactoring to make sure
202  * that brush colors are stored in scene linear by default. */
203  srgb_to_linearrgb_v3_v3(brush_color, brush_color);
204  brush_color[3] = 1.0f;
205 
206  const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
209  from_colorspace, to_colorspace);
210  IMB_colormanagement_processor_apply_v4(cm_processor, brush_color);
212  last_used_color_space = to_colorspace;
213  }
214 
215  private:
216  void init_brush_strength()
217  {
219  }
220  void init_brush_test()
221  {
222  brush_test_fn = SCULPT_brush_test_init_with_falloff_shape(ss, &test, brush->falloff_shape);
223  }
224 
228  float3 get_start_pixel_pos(const TrianglePaintInput &triangle,
229  const PackedPixelRow &encoded_pixels) const
230  {
231  return init_pixel_pos(triangle, encoded_pixels.start_barycentric_coord);
232  }
233 
238  float3 get_delta_pixel_pos(const TrianglePaintInput &triangle,
239  const PackedPixelRow &encoded_pixels,
240  const float3 &start_pixel) const
241  {
242  float3 result = init_pixel_pos(
243  triangle, encoded_pixels.start_barycentric_coord + triangle.delta_barycentric_coord_u);
244  return result - start_pixel;
245  }
246 
247  float3 init_pixel_pos(const TrianglePaintInput &triangle,
248  const float2 &barycentric_weights) const
249  {
250  const int3 &vert_indices = triangle.vert_indices;
251  float3 result;
252  const float3 barycentric(barycentric_weights.x,
256  mvert[vert_indices[0]].co,
257  mvert[vert_indices[1]].co,
258  mvert[vert_indices[2]].co,
259  barycentric);
260  return result;
261  }
262 };
263 
264 static std::vector<bool> init_triangle_brush_test(SculptSession *ss,
265  Triangles &triangles,
266  const MVert *mvert)
267 {
268  std::vector<bool> brush_test(triangles.size());
269  SculptBrushTest test;
270  SCULPT_brush_test_init(ss, &test);
271  float3 brush_min_bounds(test.location[0] - test.radius,
272  test.location[1] - test.radius,
273  test.location[2] - test.radius);
274  float3 brush_max_bounds(test.location[0] + test.radius,
275  test.location[1] + test.radius,
276  test.location[2] + test.radius);
277  for (int triangle_index = 0; triangle_index < triangles.size(); triangle_index++) {
278  TrianglePaintInput &triangle = triangles.get_paint_input(triangle_index);
279 
280  float3 triangle_min_bounds(mvert[triangle.vert_indices[0]].co);
281  float3 triangle_max_bounds(triangle_min_bounds);
282  for (int i = 1; i < 3; i++) {
283  const float3 &pos = mvert[triangle.vert_indices[i]].co;
284  triangle_min_bounds.x = min_ff(triangle_min_bounds.x, pos.x);
285  triangle_min_bounds.y = min_ff(triangle_min_bounds.y, pos.y);
286  triangle_min_bounds.z = min_ff(triangle_min_bounds.z, pos.z);
287  triangle_max_bounds.x = max_ff(triangle_max_bounds.x, pos.x);
288  triangle_max_bounds.y = max_ff(triangle_max_bounds.y, pos.y);
289  triangle_max_bounds.z = max_ff(triangle_max_bounds.z, pos.z);
290  }
291  brush_test[triangle_index] = isect_aabb_aabb_v3(
292  brush_min_bounds, brush_max_bounds, triangle_min_bounds, triangle_max_bounds);
293  }
294  return brush_test;
295 }
296 
297 static void do_paint_pixels(void *__restrict userdata,
298  const int n,
299  const TaskParallelTLS *__restrict tls)
300 {
301  TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
302  Object *ob = data->ob;
303  SculptSession *ss = ob->sculpt;
304  const Brush *brush = data->brush;
305  PBVHNode *node = data->nodes[n];
306 
308  const int thread_id = BLI_task_parallel_thread_id(tls);
310 
311  std::vector<bool> brush_test = init_triangle_brush_test(ss, node_data.triangles, mvert);
312 
313  PaintingKernel<ImageBufferFloat4> kernel_float4(ss, brush, thread_id, mvert);
314  PaintingKernel<ImageBufferByte4> kernel_byte4(ss, brush, thread_id, mvert);
315 
316  ImageUser image_user = *data->image_data.image_user;
317  bool pixels_updated = false;
318  for (UDIMTilePixels &tile_data : node_data.tiles) {
319  LISTBASE_FOREACH (ImageTile *, tile, &data->image_data.image->tiles) {
320  ImageTileWrapper image_tile(tile);
321  if (image_tile.get_tile_number() == tile_data.tile_number) {
322  image_user.tile = image_tile.get_tile_number();
323 
324  ImBuf *image_buffer = BKE_image_acquire_ibuf(data->image_data.image, &image_user, nullptr);
325  if (image_buffer == nullptr) {
326  continue;
327  }
328 
329  if (image_buffer->rect_float != nullptr) {
330  kernel_float4.init_brush_color(image_buffer);
331  }
332  else {
333  kernel_byte4.init_brush_color(image_buffer);
334  }
335 
336  for (const PackedPixelRow &pixel_row : tile_data.pixel_rows) {
337  if (!brush_test[pixel_row.triangle_index]) {
338  continue;
339  }
340  bool pixels_painted = false;
341  if (image_buffer->rect_float != nullptr) {
342  pixels_painted = kernel_float4.paint(node_data.triangles, pixel_row, image_buffer);
343  }
344  else {
345  pixels_painted = kernel_byte4.paint(node_data.triangles, pixel_row, image_buffer);
346  }
347 
348  if (pixels_painted) {
349  tile_data.mark_dirty(pixel_row);
350  }
351  }
352 
353  BKE_image_release_ibuf(data->image_data.image, image_buffer, nullptr);
354  pixels_updated |= tile_data.flags.dirty;
355  break;
356  }
357  }
358  }
359 
360  node_data.flags.dirty |= pixels_updated;
361 }
362 
363 static void undo_region_tiles(
364  ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
365 {
366  int srcx = 0, srcy = 0;
367  IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
368  *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
369  *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
370  *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
371  *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
372 }
373 
374 static void push_undo(const NodeData &node_data,
375  Image &image,
376  ImageUser &image_user,
377  const image::ImageTileWrapper &image_tile,
378  ImBuf &image_buffer,
379  ImBuf **tmpibuf)
380 {
381  for (const UDIMTileUndo &tile_undo : node_data.undo_regions) {
382  if (tile_undo.tile_number != image_tile.get_tile_number()) {
383  continue;
384  }
385  int tilex, tiley, tilew, tileh;
387  undo_region_tiles(&image_buffer,
388  tile_undo.region.xmin,
389  tile_undo.region.ymin,
390  BLI_rcti_size_x(&tile_undo.region),
391  BLI_rcti_size_y(&tile_undo.region),
392  &tilex,
393  &tiley,
394  &tilew,
395  &tileh);
396  for (int ty = tiley; ty <= tileh; ty++) {
397  for (int tx = tilex; tx <= tilew; tx++) {
398  ED_image_paint_tile_push(undo_tiles,
399  &image,
400  &image_buffer,
401  tmpibuf,
402  &image_user,
403  tx,
404  ty,
405  nullptr,
406  nullptr,
407  true,
408  true);
409  }
410  }
411  }
412 }
413 
414 static void do_push_undo_tile(void *__restrict userdata,
415  const int n,
416  const TaskParallelTLS *__restrict UNUSED(tls))
417 {
418  TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
419  PBVHNode *node = data->nodes[n];
420 
422  Image *image = data->image_data.image;
423  ImageUser *image_user = data->image_data.image_user;
424 
425  ImBuf *tmpibuf = nullptr;
426  ImageUser local_image_user = *image_user;
427  LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
428  image::ImageTileWrapper image_tile(tile);
429  local_image_user.tile = image_tile.get_tile_number();
430  ImBuf *image_buffer = BKE_image_acquire_ibuf(image, &local_image_user, nullptr);
431  if (image_buffer == nullptr) {
432  continue;
433  }
434 
435  push_undo(node_data, *image, *image_user, image_tile, *image_buffer, &tmpibuf);
436  BKE_image_release_ibuf(image, image_buffer, nullptr);
437  }
438  if (tmpibuf) {
439  IMB_freeImBuf(tmpibuf);
440  }
441 }
442 
443 static void do_mark_dirty_regions(void *__restrict userdata,
444  const int n,
445  const TaskParallelTLS *__restrict UNUSED(tls))
446 {
447  TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
448  PBVHNode *node = data->nodes[n];
449  BKE_pbvh_pixels_mark_image_dirty(*node, *data->image_data.image, *data->image_data.image_user);
450 }
451 
452 } // namespace blender::ed::sculpt_paint::paint::image
453 
454 extern "C" {
455 
457 
459  Object *ob,
460  Image **r_image,
461  ImageUser **r_image_user)
462 {
463  *r_image = nullptr;
464  *r_image_user = nullptr;
465 
466  ImageData image_data;
467  if (!ImageData::init_active_image(ob, &image_data, paint_mode_settings)) {
468  return false;
469  }
470 
471  *r_image = image_data.image;
472  *r_image_user = image_data.image_user;
473  return true;
474 }
475 
477 {
478  if (!U.experimental.use_sculpt_texture_paint) {
479  return false;
480  }
481  if (ob->type != OB_MESH) {
482  return false;
483  }
484  Image *image;
485  ImageUser *image_user;
486  return BKE_paint_canvas_image_get(settings, ob, &image, &image_user);
487 }
488 
490  PaintModeSettings *paint_mode_settings, Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
491 {
492  Brush *brush = BKE_paint_brush(&sd->paint);
493 
494  TexturePaintingUserData data = {nullptr};
495  data.ob = ob;
496  data.brush = brush;
497  data.nodes = nodes;
498 
499  if (!ImageData::init_active_image(ob, &data.image_data, paint_mode_settings)) {
500  return;
501  }
502 
503  TaskParallelSettings settings;
504  BKE_pbvh_parallel_range_settings(&settings, true, totnode);
505  BLI_task_parallel_range(0, totnode, &data, do_push_undo_tile, &settings);
506  BLI_task_parallel_range(0, totnode, &data, do_paint_pixels, &settings);
507 
508  TaskParallelSettings settings_flush;
509  BKE_pbvh_parallel_range_settings(&settings_flush, false, totnode);
510  BLI_task_parallel_range(0, totnode, &data, do_mark_dirty_regions, &settings_flush);
511 }
512 }
const float * BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush)
Definition: brush.cc:2216
const float * BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush)
Definition: brush.cc:2210
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
General operations, lookup, etc. for materials.
bool BKE_paint_canvas_image_get(struct PaintModeSettings *settings, struct Object *ob, struct Image **r_image, struct ImageUser **r_image_user)
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:607
A BVH for high poly meshes.
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, bool use_threading, int totnode)
Definition: pbvh.c:3211
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
Definition: math_color.c:383
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
Definition: math_color.c:396
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])
Definition: math_geom.c:3048
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])
Definition: math_vector.c:160
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:190
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:186
unsigned char uchar
Definition: BLI_sys_types.h:70
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls)
#define UNUSED(x)
Object is a sort of wrapper for general info.
@ OB_MESH
struct PaintTileMap * ED_image_paint_tile_map_get(void)
Definition: image_undo.cc:1061
void * ED_image_paint_tile_push(PaintTileMap *paint_tile_map, struct Image *image, struct ImBuf *ibuf, struct ImBuf **tmpibuf, struct ImageUser *iuser, int x_tile, int y_tile, unsigned short **r_mask, bool **r_valid, bool use_thread_lock, bool find_prev)
Definition: image_undo.cc:192
#define ED_IMAGE_UNDO_TILE_BITS
Definition: ED_paint.h:104
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
const char * IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf)
struct ColormanageProcessor * IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace)
@ COLOR_ROLE_SCENE_LINEAR
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor)
void IMB_colormanagement_processor_apply_v4(struct ColormanageProcessor *cm_processor, float pixel[4])
const char * IMB_colormanagement_role_colorspace_name_get(int role)
const char * IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf)
void IMB_rectclip(struct ImBuf *dbuf, const struct ImBuf *sbuf, int *destx, int *desty, int *srcx, int *srcy, int *width, int *height)
IMB_BlendMode
Definition: IMB_imbuf.h:209
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition: rectop.c:112
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
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 Triangles &triangles, const PackedPixelRow &pixel_row, ImBuf *image_buffer)
PaintingKernel(SculptSession *ss, const Brush *brush, const int thread_id, const MVert *mvert)
OperationNode * node
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
uint pos
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
IconTextureDrawCall normal
ccl_global const KernelWorkTile * tile
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static bool barycentric_weights(const float v1[3], const float v2[3], const float v3[3], const float co[3], const float n[3], float w[3])
Definition: math_geom.c:3571
#define sqrtf(x)
Definition: metal/compat.h:243
NodeData & BKE_pbvh_pixels_node_data_get(PBVHNode &node)
Definition: pbvh_pixels.cc:350
void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &image_user)
Definition: pbvh_pixels.cc:357
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 do_paint_pixels(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls)
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_mark_dirty_regions(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static void do_push_undo_tile(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static std::vector< bool > init_triangle_brush_test(SculptSession *ss, Triangles &triangles, const MVert *mvert)
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss, SculptBrushTest *test, char falloff_shape)
Definition: sculpt.c:1686
float SCULPT_brush_strength_factor(SculptSession *ss, const Brush *br, const float brush_point[3], const float len, const float vno[3], const float fno[3], const float mask, const int vertex_index, const int thread_id)
Definition: sculpt.c:2370
void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test)
Definition: sculpt.c:1532
MVert * SCULPT_mesh_deformed_mverts_get(SculptSession *ss)
Definition: sculpt.c:289
static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups, const PaintModeSettings *UNUSED(paint_mode_settings))
Definition: sculpt.c:2219
bool(* SculptBrushTestFn)(SculptBrushTest *test, const float co[3])
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.
bool SCULPT_use_image_paint_brush(PaintModeSettings *settings, Object *ob)
void SCULPT_do_paint_brush_image(PaintModeSettings *paint_mode_settings, Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float alpha
char falloff_shape
short blend
unsigned int * rect
float * rect_float
float co[3]
struct SculptSession * sculpt
struct Scene * scene
Definition: BKE_paint.h:591
struct StrokeCache * cache
Definition: BKE_paint.h:563
Paint paint
struct blender::bke::pbvh::pixels::NodeData::@58 flags
TrianglePaintInput & get_paint_input(const int index)
void mark_dirty(const PackedPixelRow &pixel_row)
struct blender::bke::pbvh::pixels::UDIMTilePixels::@57 flags
static bool init_active_image(Object *ob, ImageData *r_image_data, PaintModeSettings *paint_mode_settings)
int ymin
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63