Blender  V3.3
paint_image_2d.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
7 //#include <math.h>
8 #include <string.h>
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "DNA_brush_types.h"
13 #include "DNA_object_types.h"
14 #include "DNA_scene_types.h"
15 #include "DNA_space_types.h"
16 
17 #include "BLI_bitmap.h"
18 #include "BLI_listbase.h"
19 #include "BLI_math_color_blend.h"
20 #include "BLI_stack.h"
21 #include "BLI_task.h"
22 
23 #include "BKE_brush.h"
24 #include "BKE_colorband.h"
25 #include "BKE_context.h"
26 #include "BKE_image.h"
27 #include "BKE_paint.h"
28 #include "BKE_report.h"
29 
30 #include "DEG_depsgraph.h"
31 
32 #include "ED_paint.h"
33 #include "ED_screen.h"
34 
35 #include "IMB_colormanagement.h"
36 #include "IMB_imbuf.h"
37 #include "IMB_imbuf_types.h"
38 
39 #include "WM_api.h"
40 #include "WM_types.h"
41 
42 #include "UI_view2d.h"
43 
44 #include "paint_intern.h"
45 
46 /* Brush Painting for 2D image editor */
47 
48 /* Defines and Structs */
49 
50 typedef struct BrushPainterCache {
51  bool use_float; /* need float imbuf? */
52  bool use_color_correction; /* use color correction for float */
53  bool invert;
54 
57 
62 
69 
71 
72  int image_size[2];
74 
75 typedef struct BrushPainter {
78 
79  bool firsttouch; /* first paint op */
80 
81  struct ImagePool *pool; /* image pool */
82  rctf tex_mapping; /* texture coordinate mapping */
83  rctf mask_mapping; /* mask texture coordinate mapping */
84 
87 
88 typedef struct ImagePaintRegion {
89  int destx, desty;
90  int srcx, srcy;
91  int width, height;
93 
94 typedef enum ImagePaintTileState {
99 
100 typedef struct ImagePaintTile {
103  float radius_fac;
104  int size[2];
105  float uv_origin[2]; /* Stores the position of this tile in UV space. */
108 
110 
111  float last_paintpos[2]; /* position of last paint op */
112  float start_paintpos[2]; /* position of first paint */
114 
115 typedef struct ImagePaintState {
120 
122  short tool, blend;
125 
127 
128  int symmetry;
129 
132 
135 
137 {
138  BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
139 
140  painter->brush = brush;
141  painter->scene = scene;
142  painter->firsttouch = true;
143  painter->cache_invert = invert;
144 
145  return painter;
146 }
147 
149  Brush *brush, ImagePaintTile *tile, bool use_float, bool use_color_correction, bool invert)
150 {
151  BrushPainterCache *cache = &tile->cache;
152 
153  if ((cache->use_float != use_float)) {
154  if (cache->ibuf) {
155  IMB_freeImBuf(cache->ibuf);
156  }
157  if (cache->tex_mask) {
158  MEM_freeN(cache->tex_mask);
159  }
160  if (cache->tex_mask_old) {
161  MEM_freeN(cache->tex_mask_old);
162  }
163  cache->ibuf = NULL;
164  cache->tex_mask = NULL;
165  cache->lastdiameter = -1; /* force ibuf create in refresh */
166  }
167 
168  cache->use_float = use_float;
169  cache->use_color_correction = use_float && use_color_correction;
170  cache->invert = invert;
171  cache->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true :
172  false;
173  cache->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
174 }
175 
177 {
178  if (cache->ibuf) {
179  IMB_freeImBuf(cache->ibuf);
180  }
181  if (cache->texibuf) {
182  IMB_freeImBuf(cache->texibuf);
183  }
185  if (cache->tex_mask) {
186  MEM_freeN(cache->tex_mask);
187  }
188  if (cache->tex_mask_old) {
189  MEM_freeN(cache->tex_mask_old);
190  }
191 }
192 
193 static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
194 {
195  texco[0] = mapping->xmin + x * mapping->xmax;
196  texco[1] = mapping->ymin + y * mapping->ymax;
197  texco[2] = 0.0f;
198 }
199 
200 /* create a mask with the mask texture */
202 {
203  Scene *scene = painter->scene;
204  Brush *brush = painter->brush;
205  rctf mask_mapping = painter->mask_mapping;
206  struct ImagePool *pool = painter->pool;
207 
208  float texco[3];
209  ushort *mask, *m;
210  int x, y, thread = 0;
211 
212  mask = MEM_mallocN(sizeof(ushort) * size * size, "brush_painter_mask");
213  m = mask;
214 
215  for (y = 0; y < size; y++) {
216  for (x = 0; x < size; x++, m++) {
217  float res;
218  brush_imbuf_tex_co(&mask_mapping, x, y, texco);
219  res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
220  *m = (ushort)(65535.0f * res);
221  }
222  }
223 
224  return mask;
225 }
226 
227 /* update rectangular section of the brush image */
230  const ushort *tex_mask_old,
231  int origx,
232  int origy,
233  int w,
234  int h,
235  int xt,
236  int yt,
237  const int diameter)
238 {
239  Scene *scene = painter->scene;
240  Brush *brush = painter->brush;
241  BrushPainterCache *cache = &tile->cache;
242  rctf tex_mapping = painter->mask_mapping;
243  struct ImagePool *pool = painter->pool;
244  ushort res;
245 
246  bool use_texture_old = (tex_mask_old != NULL);
247 
248  int x, y, thread = 0;
249 
250  ushort *tex_mask = cache->tex_mask;
251  ushort *tex_mask_cur = cache->tex_mask_old;
252 
253  /* fill pixels */
254  for (y = origy; y < h; y++) {
255  for (x = origx; x < w; x++) {
256  /* sample texture */
257  float texco[3];
258 
259  /* handle byte pixel */
260  ushort *b = tex_mask + (y * diameter + x);
261  ushort *t = tex_mask_cur + (y * diameter + x);
262 
263  if (!use_texture_old) {
264  brush_imbuf_tex_co(&tex_mapping, x, y, texco);
265  res = (ushort)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
266  }
267 
268  /* read from old texture buffer */
269  if (use_texture_old) {
270  res = *(tex_mask_old + ((y - origy + yt) * cache->tex_mask_old_w + (x - origx + xt)));
271  }
272 
273  /* write to new texture mask */
274  *t = res;
275  /* write to mask image buffer */
276  *b = res;
277  }
278  }
279 }
280 
288  const float pos[2],
289  const int diameter)
290 {
291  BrushPainterCache *cache = &tile->cache;
292  ushort *tex_mask_old;
293  int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
294 
295  /* create brush image buffer if it didn't exist yet */
296  if (!cache->tex_mask) {
297  cache->tex_mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
298  }
299 
300  /* create new texture image buffer with coordinates relative to old */
301  tex_mask_old = cache->tex_mask_old;
302  cache->tex_mask_old = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
303 
304  if (tex_mask_old) {
305  ImBuf maskibuf;
306  ImBuf maskibuf_old;
307  maskibuf.x = diameter;
308  maskibuf.y = diameter;
309  maskibuf_old.x = cache->tex_mask_old_w;
310  maskibuf_old.y = cache->tex_mask_old_h;
311 
312  srcx = srcy = 0;
313  w = cache->tex_mask_old_w;
314  h = cache->tex_mask_old_h;
315  destx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
316  desty = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
317 
318  /* hack, use temporary rects so that clipping works */
319  IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
320  }
321  else {
322  srcx = srcy = 0;
323  destx = desty = 0;
324  w = h = 0;
325  }
326 
327  x1 = min_ii(destx, diameter);
328  y1 = min_ii(desty, diameter);
329  x2 = min_ii(destx + w, diameter);
330  y2 = min_ii(desty + h, diameter);
331 
332  /* blend existing texture in new position */
333  if ((x1 < x2) && (y1 < y2)) {
335  painter, tile, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
336  }
337 
338  if (tex_mask_old) {
339  MEM_freeN(tex_mask_old);
340  }
341 
342  /* sample texture in new areas */
343  if ((0 < x1) && (0 < diameter)) {
344  brush_painter_mask_imbuf_update(painter, tile, NULL, 0, 0, x1, diameter, 0, 0, diameter);
345  }
346  if ((x2 < diameter) && (0 < diameter)) {
348  painter, tile, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
349  }
350  if ((x1 < x2) && (0 < y1)) {
351  brush_painter_mask_imbuf_update(painter, tile, NULL, x1, 0, x2, y1, 0, 0, diameter);
352  }
353  if ((x1 < x2) && (y2 < diameter)) {
354  brush_painter_mask_imbuf_update(painter, tile, NULL, x1, y2, x2, diameter, 0, 0, diameter);
355  }
356 
357  /* through with sampling, now update sizes */
358  cache->tex_mask_old_w = diameter;
359  cache->tex_mask_old_h = diameter;
360 }
361 
362 /* create imbuf with brush color */
364  BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance)
365 {
366  Scene *scene = painter->scene;
367  Brush *brush = painter->brush;
368  BrushPainterCache *cache = &tile->cache;
369 
370  const char *display_device = scene->display_settings.display_device;
371  struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
372 
373  rctf tex_mapping = painter->tex_mapping;
374  struct ImagePool *pool = painter->pool;
375 
376  bool use_color_correction = cache->use_color_correction;
377  bool use_float = cache->use_float;
378  bool is_texbrush = cache->is_texbrush;
379 
380  int x, y, thread = 0;
381  float brush_rgb[3];
382 
383  /* allocate image buffer */
384  ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect);
385 
386  /* get brush color */
387  if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
389  scene, brush, use_color_correction, cache->invert, distance, pressure, brush_rgb, display);
390  }
391  else {
392  brush_rgb[0] = 1.0f;
393  brush_rgb[1] = 1.0f;
394  brush_rgb[2] = 1.0f;
395  }
396 
397  /* fill image buffer */
398  for (y = 0; y < size; y++) {
399  for (x = 0; x < size; x++) {
400  /* sample texture and multiply with brush color */
401  float texco[3], rgba[4];
402 
403  if (is_texbrush) {
404  brush_imbuf_tex_co(&tex_mapping, x, y, texco);
405  BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
406  /* TODO(sergey): Support texture paint color space. */
407  if (!use_float) {
409  }
410  mul_v3_v3(rgba, brush_rgb);
411  }
412  else {
413  copy_v3_v3(rgba, brush_rgb);
414  rgba[3] = 1.0f;
415  }
416 
417  if (use_float) {
418  /* write to float pixel */
419  float *dstf = ibuf->rect_float + (y * size + x) * 4;
420  mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */
421  dstf[3] = rgba[3];
422  }
423  else {
424  /* write to byte pixel */
425  uchar *dst = (uchar *)ibuf->rect + (y * size + x) * 4;
426 
427  rgb_float_to_uchar(dst, rgba);
428  dst[3] = unit_float_to_uchar_clamp(rgba[3]);
429  }
430  }
431  }
432 
433  return ibuf;
434 }
435 
436 /* update rectangular section of the brush image */
439  ImBuf *oldtexibuf,
440  int origx,
441  int origy,
442  int w,
443  int h,
444  int xt,
445  int yt)
446 {
447  Scene *scene = painter->scene;
448  Brush *brush = painter->brush;
449  BrushPainterCache *cache = &tile->cache;
450 
451  const char *display_device = scene->display_settings.display_device;
452  struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
453 
454  rctf tex_mapping = painter->tex_mapping;
455  struct ImagePool *pool = painter->pool;
456 
457  bool use_color_correction = cache->use_color_correction;
458  bool use_float = cache->use_float;
459  bool is_texbrush = cache->is_texbrush;
460  bool use_texture_old = (oldtexibuf != NULL);
461 
462  int x, y, thread = 0;
463  float brush_rgb[3];
464 
465  ImBuf *ibuf = cache->ibuf;
466  ImBuf *texibuf = cache->texibuf;
467 
468  /* get brush color */
469  if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
471  scene, brush, use_color_correction, cache->invert, 0.0f, 1.0f, brush_rgb, display);
472  }
473  else {
474  brush_rgb[0] = 1.0f;
475  brush_rgb[1] = 1.0f;
476  brush_rgb[2] = 1.0f;
477  }
478 
479  /* fill pixels */
480  for (y = origy; y < h; y++) {
481  for (x = origx; x < w; x++) {
482  /* sample texture and multiply with brush color */
483  float texco[3], rgba[4];
484 
485  if (!use_texture_old) {
486  if (is_texbrush) {
487  brush_imbuf_tex_co(&tex_mapping, x, y, texco);
488  BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool);
489  /* TODO(sergey): Support texture paint color space. */
490  if (!use_float) {
492  }
493  mul_v3_v3(rgba, brush_rgb);
494  }
495  else {
496  copy_v3_v3(rgba, brush_rgb);
497  rgba[3] = 1.0f;
498  }
499  }
500 
501  if (use_float) {
502  /* handle float pixel */
503  float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4;
504  float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4;
505 
506  /* read from old texture buffer */
507  if (use_texture_old) {
508  const float *otf = oldtexibuf->rect_float +
509  ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
510  copy_v4_v4(rgba, otf);
511  }
512 
513  /* write to new texture buffer */
514  copy_v4_v4(tf, rgba);
515 
516  /* output premultiplied float image, mf was already premultiplied */
517  mul_v3_v3fl(bf, rgba, rgba[3]);
518  bf[3] = rgba[3];
519  }
520  else {
521  uchar crgba[4];
522 
523  /* handle byte pixel */
524  uchar *b = (uchar *)ibuf->rect + (y * ibuf->x + x) * 4;
525  uchar *t = (uchar *)texibuf->rect + (y * texibuf->x + x) * 4;
526 
527  /* read from old texture buffer */
528  if (use_texture_old) {
529  uchar *ot = (uchar *)oldtexibuf->rect +
530  ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
531  crgba[0] = ot[0];
532  crgba[1] = ot[1];
533  crgba[2] = ot[2];
534  crgba[3] = ot[3];
535  }
536  else {
537  rgba_float_to_uchar(crgba, rgba);
538  }
539 
540  /* write to new texture buffer */
541  t[0] = crgba[0];
542  t[1] = crgba[1];
543  t[2] = crgba[2];
544  t[3] = crgba[3];
545 
546  /* write to brush image buffer */
547  b[0] = crgba[0];
548  b[1] = crgba[1];
549  b[2] = crgba[2];
550  b[3] = crgba[3];
551  }
552  }
553  }
554 }
555 
556 /* update the brush image by trying to reuse the cached texture result. this
557  * can be considerably faster for brushes that change size due to pressure or
558  * textures that stick to the surface where only part of the pixels are new */
561  const float pos[2],
562  const int diameter)
563 {
564  BrushPainterCache *cache = &tile->cache;
565  ImBuf *oldtexibuf, *ibuf;
566  int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
567 
568  /* create brush image buffer if it didn't exist yet */
569  imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
570  if (!cache->ibuf) {
571  cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
572  }
573  ibuf = cache->ibuf;
574 
575  /* create new texture image buffer with coordinates relative to old */
576  oldtexibuf = cache->texibuf;
577  cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
578 
579  if (oldtexibuf) {
580  srcx = srcy = 0;
581  w = oldtexibuf->x;
582  h = oldtexibuf->y;
583  destx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
584  desty = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
585 
586  IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
587  }
588  else {
589  srcx = srcy = 0;
590  destx = desty = 0;
591  w = h = 0;
592  }
593 
594  x1 = min_ii(destx, ibuf->x);
595  y1 = min_ii(desty, ibuf->y);
596  x2 = min_ii(destx + w, ibuf->x);
597  y2 = min_ii(desty + h, ibuf->y);
598 
599  /* blend existing texture in new position */
600  if ((x1 < x2) && (y1 < y2)) {
601  brush_painter_imbuf_update(painter, tile, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
602  }
603 
604  if (oldtexibuf) {
605  IMB_freeImBuf(oldtexibuf);
606  }
607 
608  /* sample texture in new areas */
609  if ((0 < x1) && (0 < ibuf->y)) {
610  brush_painter_imbuf_update(painter, tile, NULL, 0, 0, x1, ibuf->y, 0, 0);
611  }
612  if ((x2 < ibuf->x) && (0 < ibuf->y)) {
613  brush_painter_imbuf_update(painter, tile, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
614  }
615  if ((x1 < x2) && (0 < y1)) {
616  brush_painter_imbuf_update(painter, tile, NULL, x1, 0, x2, y1, 0, 0);
617  }
618  if ((x1 < x2) && (y2 < ibuf->y)) {
619  brush_painter_imbuf_update(painter, tile, NULL, x1, y2, x2, ibuf->y, 0, 0);
620  }
621 }
622 
625  const int diameter,
626  const float pos[2],
627  const float mouse[2],
628  int mapmode,
629  rctf *mapping)
630 {
631  float invw = 1.0f / (float)tile->canvas->x;
632  float invh = 1.0f / (float)tile->canvas->y;
633  float start[2];
634 
635  /* find start coordinate of brush in canvas */
636  start[0] = pos[0] - diameter / 2.0f;
637  start[1] = pos[1] - diameter / 2.0f;
638 
639  if (mapmode == MTEX_MAP_MODE_STENCIL) {
640  /* map from view coordinates of brush to region coordinates */
641  float xmin, ymin, xmax, ymax;
642  UI_view2d_view_to_region_fl(s->v2d, start[0] * invw, start[1] * invh, &xmin, &ymin);
644  s->v2d, (start[0] + diameter) * invw, (start[1] + diameter) * invh, &xmax, &ymax);
645 
646  /* output mapping from brush ibuf x/y to region coordinates */
647  mapping->xmax = (xmax - xmin) / (float)diameter;
648  mapping->ymax = (ymax - ymin) / (float)diameter;
649  mapping->xmin = xmin + (tile->uv_origin[0] * tile->size[0] * mapping->xmax);
650  mapping->ymin = ymin + (tile->uv_origin[1] * tile->size[1] * mapping->ymax);
651  }
652  else if (mapmode == MTEX_MAP_MODE_3D) {
653  /* 3D mapping, just mapping to canvas 0..1. */
654  mapping->xmin = 2.0f * (start[0] * invw - 0.5f);
655  mapping->ymin = 2.0f * (start[1] * invh - 0.5f);
656  mapping->xmax = 2.0f * invw;
657  mapping->ymax = 2.0f * invh;
658  }
659  else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
660  /* view mapping */
661  mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
662  mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
663  mapping->xmax = 1.0f;
664  mapping->ymax = 1.0f;
665  }
666  else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
667  mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) -
668  (int)floorf(tile->start_paintpos[0]);
669  mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) -
670  (int)floorf(tile->start_paintpos[1]);
671  mapping->xmax = 1.0f;
672  mapping->ymax = 1.0f;
673  }
674 }
675 
677  BrushPainter *painter,
679  const float pos[2],
680  const float mouse[2],
681  float pressure,
682  float distance,
683  float size)
684 {
685  const Scene *scene = painter->scene;
687  Brush *brush = painter->brush;
688  BrushPainterCache *cache = &tile->cache;
689  /* Adding 4 pixels of padding for brush antialiasing */
690  const int diameter = MAX2(1, size * 2) + 4;
691 
692  bool do_random = false;
693  bool do_partial_update = false;
694  bool update_color = ((brush->flag & BRUSH_USE_GRADIENT) && (ELEM(brush->gradient_stroke_mode,
697  (cache->last_pressure != pressure)));
698  float tex_rotation = -brush->mtex.rot;
699  float mask_rotation = -brush->mask_mtex.rot;
700 
701  painter->pool = BKE_image_pool_new();
702 
703  /* determine how can update based on textures used */
704  if (cache->is_texbrush) {
705  if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
706  tex_rotation += ups->brush_rotation;
707  }
708  else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
709  do_random = true;
710  }
711  else if (!((brush->flag & BRUSH_ANCHORED) || update_color)) {
712  do_partial_update = true;
713  }
714 
716  s, tile, diameter, pos, mouse, brush->mtex.brush_map_mode, &painter->tex_mapping);
717  }
718 
719  if (cache->is_maskbrush) {
720  bool renew_maxmask = false;
721  bool do_partial_update_mask = false;
722  /* invalidate case for all mapping modes */
724  mask_rotation += ups->brush_rotation_sec;
725  }
726  else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
727  renew_maxmask = true;
728  }
729  else if (!(brush->flag & BRUSH_ANCHORED)) {
730  do_partial_update_mask = true;
731  renew_maxmask = true;
732  }
733  /* explicitly disable partial update even if it has been enabled above */
734  if (brush->mask_pressure) {
735  do_partial_update_mask = false;
736  renew_maxmask = true;
737  }
738 
739  if (diameter != cache->lastdiameter || (mask_rotation != cache->last_mask_rotation) ||
740  renew_maxmask) {
741  MEM_SAFE_FREE(cache->tex_mask);
742 
744  s, tile, diameter, pos, mouse, brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
745 
746  if (do_partial_update_mask) {
747  brush_painter_mask_imbuf_partial_update(painter, tile, pos, diameter);
748  }
749  else {
750  cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
751  }
752  cache->last_mask_rotation = mask_rotation;
753  }
754  }
755 
756  /* Re-initialize the curve mask. Mask is always recreated due to the change of position. */
757  paint_curve_mask_cache_update(&cache->curve_mask_cache, brush, diameter, size, pos);
758 
759  /* detect if we need to recreate image brush buffer */
760  if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random ||
761  update_color) {
762  if (cache->ibuf) {
763  IMB_freeImBuf(cache->ibuf);
764  cache->ibuf = NULL;
765  }
766 
767  if (do_partial_update) {
768  /* do partial update of texture */
769  brush_painter_imbuf_partial_update(painter, tile, pos, diameter);
770  }
771  else {
772  /* create brush from scratch */
773  cache->ibuf = brush_painter_imbuf_new(painter, tile, diameter, pressure, distance);
774  }
775 
776  cache->lastdiameter = diameter;
777  cache->last_tex_rotation = tex_rotation;
778  cache->last_pressure = pressure;
779  }
780  else if (do_partial_update) {
781  /* do only partial update of texture */
782  int dx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]);
783  int dy = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]);
784 
785  if ((dx != 0) || (dy != 0)) {
786  brush_painter_imbuf_partial_update(painter, tile, pos, diameter);
787  }
788  }
789 
790  BKE_image_pool_free(painter->pool);
791  painter->pool = NULL;
792 }
793 
795 {
796  if (i == 0) {
797  return true;
798  }
799  if (i >= s->num_tiles) {
800  return false;
801  }
802 
803  if (s->tiles[i].state == PAINT2D_TILE_READY) {
804  return true;
805  }
806  if (s->tiles[i].state == PAINT2D_TILE_MISSING) {
807  return false;
808  }
809 
810  s->tiles[i].cache.lastdiameter = -1;
811 
812  ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[i].iuser, NULL);
813  if (ibuf != NULL) {
814  if (ibuf->channels != 4) {
816  }
817  else if ((s->tiles[0].canvas->rect && !ibuf->rect) ||
818  (s->tiles[0].canvas->rect_float && !ibuf->rect_float)) {
820  }
821  else {
822  s->tiles[i].size[0] = ibuf->x;
823  s->tiles[i].size[1] = ibuf->y;
824  s->tiles[i].radius_fac = sqrtf(((float)ibuf->x * (float)ibuf->y) /
825  (s->tiles[0].size[0] * s->tiles[0].size[1]));
827  }
828  }
829  else {
831  }
832 
833  if (s->tiles[i].state == PAINT2D_TILE_MISSING) {
834  BKE_image_release_ibuf(s->image, ibuf, NULL);
835  return false;
836  }
837 
838  s->tiles[i].canvas = ibuf;
839  return true;
840 }
841 
842 /* keep these functions in sync */
843 static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
844 {
845  if (ibuf->rect_float) {
846  const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
847  copy_v4_v4(r_rgb, rrgbf);
848  }
849  else {
850  uchar *rrgb = (uchar *)ibuf->rect + (ibuf->x * y + x) * 4;
851  straight_uchar_to_premul_float(r_rgb, rrgb);
852  }
853 }
855  ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
856 {
857  if (is_torus) {
858  x %= ibuf->x;
859  if (x < 0) {
860  x += ibuf->x;
861  }
862  y %= ibuf->y;
863  if (y < 0) {
864  y += ibuf->y;
865  }
866  }
867 
868  if (ibuf->rect_float) {
869  float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
870  float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];
871 
872  mul_v3_v3fl(rrgbf, rgb, map_alpha);
873  rrgbf[3] = rgb[3];
874  }
875  else {
876  uchar straight[4];
877  uchar *rrgb = (uchar *)ibuf->rect + (ibuf->x * y + x) * 4;
878 
880  rrgb[0] = straight[0];
881  rrgb[1] = straight[1];
882  rrgb[2] = straight[2];
883  rrgb[3] = straight[3];
884  }
885 }
886 
887 static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short paint_tile)
888 {
889  if (paint_tile & PAINT_TILE_X) {
890  *x %= ibuf->x;
891  if (*x < 0) {
892  *x += ibuf->x;
893  }
894  }
895  if (paint_tile & PAINT_TILE_Y) {
896  *y %= ibuf->y;
897  if (*y < 0) {
898  *y += ibuf->y;
899  }
900  }
901 }
902 
903 static float paint_2d_ibuf_add_if(
904  ImBuf *ibuf, int x, int y, float *outrgb, short paint_tile, float w)
905 {
906  float inrgb[4];
907 
908  if (paint_tile) {
909  paint_2d_ibuf_tile_convert(ibuf, &x, &y, paint_tile);
910  }
911  /* need to also do clipping here always since tiled coordinates
912  * are not always within bounds */
913  if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
914  paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
915  }
916  else {
917  return 0.0f;
918  }
919 
920  mul_v4_fl(inrgb, w);
921  add_v4_v4(outrgb, inrgb);
922 
923  return w;
924 }
925 
928  ImBuf *ibuf,
929  ImBuf *ibufb,
930  const int *pos,
931  const short paint_tile)
932 {
933  bool sharpen = (tile->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
934  float threshold = s->brush->sharp_threshold;
935  int x, y, xi, yi, xo, yo, xk, yk;
936  float count;
937  int out_off[2], in_off[2], dim[2];
938  int diff_pos[2];
939  float outrgb[4];
940  float rgba[4];
942 
943  dim[0] = ibufb->x;
944  dim[1] = ibufb->y;
945  in_off[0] = pos[0];
946  in_off[1] = pos[1];
947  out_off[0] = out_off[1] = 0;
948 
949  if (!paint_tile) {
950  IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], &out_off[1], &dim[0], &dim[1]);
951 
952  if ((dim[0] == 0) || (dim[1] == 0)) {
953  return;
954  }
955  }
956 
957  /* find offset inside mask buffers to sample them */
958  sub_v2_v2v2_int(diff_pos, out_off, in_off);
959 
960  for (y = 0; y < dim[1]; y++) {
961  for (x = 0; x < dim[0]; x++) {
962  /* get input pixel */
963  xi = in_off[0] + x;
964  yi = in_off[1] + y;
965 
966  count = 0.0;
967  if (paint_tile) {
968  paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, paint_tile);
969  if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0) {
970  paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
971  }
972  else {
973  zero_v4(rgba);
974  }
975  }
976  else {
977  /* coordinates have been clipped properly here, it should be safe to do this */
978  paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
979  }
980  zero_v4(outrgb);
981 
982  for (yk = 0; yk < kernel->side; yk++) {
983  for (xk = 0; xk < kernel->side; xk++) {
984  count += paint_2d_ibuf_add_if(ibuf,
985  xi + xk - kernel->pixel_len,
986  yi + yk - kernel->pixel_len,
987  outrgb,
988  paint_tile,
989  kernel->wdata[xk + yk * kernel->side]);
990  }
991  }
992 
993  if (count > 0.0f) {
994  mul_v4_fl(outrgb, 1.0f / (float)count);
995 
996  if (sharpen) {
997  /* subtract blurred image from normal image gives high pass filter */
998  sub_v3_v3v3(outrgb, rgba, outrgb);
999 
1000  /* Now rgba_ub contains the edge result, but this should be converted to luminance to
1001  * avoid colored speckles appearing in final image, and also to check for threshold. */
1002  outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
1003  if (fabsf(outrgb[0]) > threshold) {
1004  float mask = BKE_brush_alpha_get(s->scene, s->brush);
1005  float alpha = rgba[3];
1006  rgba[3] = outrgb[3] = mask;
1007 
1008  /* add to enhance edges */
1009  blend_color_add_float(outrgb, rgba, outrgb);
1010  outrgb[3] = alpha;
1011  }
1012  else {
1013  copy_v4_v4(outrgb, rgba);
1014  }
1015  }
1016  }
1017  else {
1018  copy_v4_v4(outrgb, rgba);
1019  }
1020  /* write into brush buffer */
1021  xo = out_off[0] + x;
1022  yo = out_off[1] + y;
1023  paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
1024  }
1025  }
1026 }
1027 
1029  ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
1030 {
1031  region->destx = destx;
1032  region->desty = desty;
1033  region->srcx = srcx;
1034  region->srcy = srcy;
1035  region->width = width;
1036  region->height = height;
1037 }
1038 
1040  ImBuf *dbuf,
1041  ImBuf *sbuf,
1042  short paint_tile)
1043 {
1044  int destx = region->destx;
1045  int desty = region->desty;
1046  int srcx = region->srcx;
1047  int srcy = region->srcy;
1048  int width = region->width;
1049  int height = region->height;
1050  int origw, origh, w, h, tot = 0;
1051 
1052  /* convert destination and source coordinates to be within image */
1053  if (paint_tile & PAINT_TILE_X) {
1054  destx = destx % dbuf->x;
1055  if (destx < 0) {
1056  destx += dbuf->x;
1057  }
1058  srcx = srcx % sbuf->x;
1059  if (srcx < 0) {
1060  srcx += sbuf->x;
1061  }
1062  }
1063  if (paint_tile & PAINT_TILE_Y) {
1064  desty = desty % dbuf->y;
1065  if (desty < 0) {
1066  desty += dbuf->y;
1067  }
1068  srcy = srcy % sbuf->y;
1069  if (srcy < 0) {
1070  srcy += sbuf->y;
1071  }
1072  }
1073  /* clip width of blending area to destination imbuf, to avoid writing the
1074  * same pixel twice */
1075  origw = w = (width > dbuf->x) ? dbuf->x : width;
1076  origh = h = (height > dbuf->y) ? dbuf->y : height;
1077 
1078  /* clip within image */
1079  IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
1080  paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
1081 
1082  /* do 3 other rects if needed */
1083  if ((paint_tile & PAINT_TILE_X) && w < origw) {
1085  &region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
1086  }
1087  if ((paint_tile & PAINT_TILE_Y) && h < origh) {
1089  &region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
1090  }
1091  if ((paint_tile & PAINT_TILE_X) && (paint_tile & PAINT_TILE_Y) && (w < origw) && (h < origh)) {
1092  paint_2d_set_region(&region[tot++],
1093  (destx + w) % dbuf->x,
1094  (desty + h) % dbuf->y,
1095  (srcx + w) % sbuf->x,
1096  (srcy + h) % sbuf->y,
1097  origw - w,
1098  origh - h);
1099  }
1100 
1101  return tot;
1102 }
1103 
1104 static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short paint_tile)
1105 {
1106  ImagePaintRegion region[4];
1107  int a, tot;
1108 
1109  paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
1110  tot = paint_2d_torus_split_region(region, ibufb, ibuf, paint_tile);
1111 
1112  for (a = 0; a < tot; a++) {
1113  IMB_rectblend(ibufb,
1114  ibufb,
1115  ibuf,
1116  NULL,
1117  NULL,
1118  NULL,
1119  0,
1120  region[a].destx,
1121  region[a].desty,
1122  region[a].destx,
1123  region[a].desty,
1124  region[a].srcx,
1125  region[a].srcy,
1126  region[a].width,
1127  region[a].height,
1129  false);
1130  }
1131 }
1132 
1133 static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, const int *pos)
1134 {
1135  /* NOTE: allocImbuf returns zero'd memory, so regions outside image will
1136  * have zero alpha, and hence not be blended onto the image */
1137  int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
1138  ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
1139 
1140  IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
1141  IMB_rectblend(clonebuf,
1142  clonebuf,
1143  ibufb,
1144  NULL,
1145  NULL,
1146  NULL,
1147  0,
1148  destx,
1149  desty,
1150  destx,
1151  desty,
1152  destx,
1153  desty,
1154  w,
1155  h,
1157  false);
1158  IMB_rectblend(clonebuf,
1159  clonebuf,
1160  ibuf,
1161  NULL,
1162  NULL,
1163  NULL,
1164  0,
1165  destx,
1166  desty,
1167  destx,
1168  desty,
1169  srcx,
1170  srcy,
1171  w,
1172  h,
1174  false);
1175 
1176  return clonebuf;
1177 }
1178 
1179 static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
1180 {
1181  ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
1182  ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
1183 }
1184 
1187  ImagePaintRegion *region,
1188  ImBuf *frombuf,
1189  float mask_max,
1190  short blend,
1191  int tilex,
1192  int tiley,
1193  int tilew,
1194  int tileh)
1195 {
1196  ImBuf tmpbuf;
1198 
1199  PaintTileMap *undo_tiles = ED_image_paint_tile_map_get();
1200 
1201  for (int ty = tiley; ty <= tileh; ty++) {
1202  for (int tx = tilex; tx <= tilew; tx++) {
1203  /* retrieve original pixels + mask from undo buffer */
1204  ushort *mask;
1205  int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
1206  int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
1207 
1208  if (tile->canvas->rect_float) {
1210  undo_tiles, s->image, tile->canvas, &tile->iuser, tx, ty, &mask, false);
1211  }
1212  else {
1213  tmpbuf.rect = ED_image_paint_tile_find(
1214  undo_tiles, s->image, tile->canvas, &tile->iuser, tx, ty, &mask, false);
1215  }
1216 
1217  IMB_rectblend(tile->canvas,
1218  &tmpbuf,
1219  frombuf,
1220  mask,
1221  tile->cache.curve_mask_cache.curve_mask,
1222  tile->cache.tex_mask,
1223  mask_max,
1224  region->destx,
1225  region->desty,
1226  origx,
1227  origy,
1228  region->srcx,
1229  region->srcy,
1230  region->width,
1231  region->height,
1232  blend,
1233  ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
1234  }
1235  }
1236 }
1237 
1238 typedef struct Paint2DForeachData {
1243  float mask_max;
1244  short blend;
1245  int tilex;
1246  int tilew;
1248 
1249 static void paint_2d_op_foreach_do(void *__restrict data_v,
1250  const int iter,
1251  const TaskParallelTLS *__restrict UNUSED(tls))
1252 {
1255  data->tile,
1256  data->region,
1257  data->frombuf,
1258  data->mask_max,
1259  data->blend,
1260  data->tilex,
1261  iter,
1262  data->tilew,
1263  iter);
1264 }
1265 
1266 static int paint_2d_op(void *state,
1268  const float lastpos[2],
1269  const float pos[2])
1270 {
1272  ImBuf *clonebuf = NULL, *frombuf;
1273  ImBuf *canvas = tile->canvas;
1274  ImBuf *ibufb = tile->cache.ibuf;
1275  ImagePaintRegion region[4];
1276  short paint_tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
1277  short blend = s->blend;
1278  const float *offset = s->brush->clone.offset;
1279  float liftpos[2];
1280  float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
1281  int bpos[2], blastpos[2], bliftpos[2];
1282  int a, tot;
1283 
1284  paint_2d_convert_brushco(ibufb, pos, bpos);
1285 
1286  /* lift from canvas */
1287  if (s->tool == PAINT_TOOL_SOFTEN) {
1288  paint_2d_lift_soften(s, tile, canvas, ibufb, bpos, paint_tile);
1290  }
1291  else if (s->tool == PAINT_TOOL_SMEAR) {
1292  if (lastpos[0] == pos[0] && lastpos[1] == pos[1]) {
1293  return 0;
1294  }
1295 
1296  paint_2d_convert_brushco(ibufb, lastpos, blastpos);
1297  paint_2d_lift_smear(canvas, ibufb, blastpos, paint_tile);
1299  }
1300  else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
1301  liftpos[0] = pos[0] - offset[0] * canvas->x;
1302  liftpos[1] = pos[1] - offset[1] * canvas->y;
1303 
1304  paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
1305  clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
1306  }
1307 
1308  frombuf = (clonebuf) ? clonebuf : ibufb;
1309 
1310  if (paint_tile) {
1311  paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
1312  tot = paint_2d_torus_split_region(region, canvas, frombuf, paint_tile);
1313  }
1314  else {
1315  paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
1316  tot = 1;
1317  }
1318 
1319  /* blend into canvas */
1320  for (a = 0; a < tot; a++) {
1322  canvas,
1323  &tile->iuser,
1324  region[a].destx,
1325  region[a].desty,
1326  region[a].width,
1327  region[a].height,
1328  true);
1329 
1330  if (s->do_masking) {
1331  /* masking, find original pixels tiles from undo buffer to composite over */
1332  int tilex, tiley, tilew, tileh;
1333 
1334  imapaint_region_tiles(canvas,
1335  region[a].destx,
1336  region[a].desty,
1337  region[a].width,
1338  region[a].height,
1339  &tilex,
1340  &tiley,
1341  &tilew,
1342  &tileh);
1343 
1344  if (tiley == tileh) {
1346  s, tile, &region[a], frombuf, mask_max, blend, tilex, tiley, tilew, tileh);
1347  }
1348  else {
1350  data.s = s;
1351  data.tile = tile;
1352  data.region = &region[a];
1353  data.frombuf = frombuf;
1354  data.mask_max = mask_max;
1355  data.blend = blend;
1356  data.tilex = tilex;
1357  data.tilew = tilew;
1358 
1359  TaskParallelSettings settings;
1361  BLI_task_parallel_range(tiley, tileh + 1, &data, paint_2d_op_foreach_do, &settings);
1362  }
1363  }
1364  else {
1365  /* no masking, composite brush directly onto canvas */
1366  IMB_rectblend_threaded(canvas,
1367  canvas,
1368  frombuf,
1369  NULL,
1370  tile->cache.curve_mask_cache.curve_mask,
1371  tile->cache.tex_mask,
1372  mask_max,
1373  region[a].destx,
1374  region[a].desty,
1375  region[a].destx,
1376  region[a].desty,
1377  region[a].srcx,
1378  region[a].srcy,
1379  region[a].width,
1380  region[a].height,
1381  blend,
1382  false);
1383  }
1384  }
1385 
1386  if (clonebuf) {
1387  IMB_freeImBuf(clonebuf);
1388  }
1389 
1390  return 1;
1391 }
1392 
1394 {
1395  /* set clone canvas */
1396  if (s->tool == PAINT_TOOL_CLONE) {
1397  Image *ima = s->brush->clone.image;
1398  ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
1399 
1400  if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
1401  BKE_image_release_ibuf(ima, ibuf, NULL);
1402  return 0;
1403  }
1404 
1405  s->clonecanvas = ibuf;
1406 
1407  /* temporarily add float rect for cloning */
1408  if (s->tiles[0].canvas->rect_float && !s->clonecanvas->rect_float) {
1410  }
1411  else if (!s->tiles[0].canvas->rect_float && !s->clonecanvas->rect) {
1413  }
1414  }
1415 
1416  /* set masking */
1418 
1419  return 1;
1420 }
1421 
1423 {
1424  for (int i = 0; i < s->num_tiles; i++) {
1426  }
1428 
1429  if (s->blurkernel) {
1431  MEM_freeN(s->blurkernel);
1432  }
1433 }
1434 
1435 static void paint_2d_transform_mouse(View2D *v2d, const float in[2], float out[2])
1436 {
1437  UI_view2d_region_to_view(v2d, in[0], in[1], &out[0], &out[1]);
1438 }
1439 
1440 static bool is_inside_tile(const int size[2], const float pos[2], const float brush[2])
1441 {
1442  return (pos[0] >= -brush[0]) && (pos[0] < size[0] + brush[0]) && (pos[1] >= -brush[1]) &&
1443  (pos[1] < size[1] + brush[1]);
1444 }
1445 
1446 static void paint_2d_uv_to_coord(ImagePaintTile *tile, const float uv[2], float coord[2])
1447 {
1448  coord[0] = (uv[0] - tile->uv_origin[0]) * tile->size[0];
1449  coord[1] = (uv[1] - tile->uv_origin[1]) * tile->size[1];
1450 }
1451 
1452 void paint_2d_stroke(void *ps,
1453  const float prev_mval[2],
1454  const float mval[2],
1455  const bool eraser,
1456  float pressure,
1457  float distance,
1458  float base_size)
1459 {
1460  float new_uv[2], old_uv[2];
1461  ImagePaintState *s = ps;
1462  BrushPainter *painter = s->painter;
1463 
1464  const bool is_data = s->tiles[0].canvas->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
1465 
1466  s->blend = s->brush->blend;
1467  if (eraser) {
1469  }
1470 
1471  UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &new_uv[0], &new_uv[1]);
1472  UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &old_uv[0], &old_uv[1]);
1473 
1474  float last_uv[2], start_uv[2];
1475  UI_view2d_region_to_view(s->v2d, 0.0f, 0.0f, &start_uv[0], &start_uv[1]);
1476  if (painter->firsttouch) {
1477  /* paint exactly once on first touch */
1478  copy_v2_v2(last_uv, new_uv);
1479  }
1480  else {
1481  copy_v2_v2(last_uv, old_uv);
1482  }
1483 
1484  const float uv_brush_size[2] = {
1485  (s->symmetry & PAINT_TILE_X) ? FLT_MAX : base_size / s->tiles[0].size[0],
1486  (s->symmetry & PAINT_TILE_Y) ? FLT_MAX : base_size / s->tiles[0].size[1]};
1487 
1488  for (int i = 0; i < s->num_tiles; i++) {
1489  ImagePaintTile *tile = &s->tiles[i];
1490 
1491  /* First test: Project brush into UV space, clip against tile. */
1492  const int uv_size[2] = {1, 1};
1493  float local_new_uv[2], local_old_uv[2];
1494  sub_v2_v2v2(local_new_uv, new_uv, tile->uv_origin);
1495  sub_v2_v2v2(local_old_uv, old_uv, tile->uv_origin);
1496  if (!(is_inside_tile(uv_size, local_new_uv, uv_brush_size) ||
1497  is_inside_tile(uv_size, local_old_uv, uv_brush_size))) {
1498  continue;
1499  }
1500 
1501  /* Lazy tile loading to get size in pixels. */
1502  if (!paint_2d_ensure_tile_canvas(s, i)) {
1503  continue;
1504  }
1505 
1506  float size = base_size * tile->radius_fac;
1507 
1508  float new_coord[2], old_coord[2];
1509  paint_2d_uv_to_coord(tile, new_uv, new_coord);
1510  paint_2d_uv_to_coord(tile, old_uv, old_coord);
1511  if (painter->firsttouch) {
1512  paint_2d_uv_to_coord(tile, start_uv, tile->start_paintpos);
1513  }
1514  paint_2d_uv_to_coord(tile, last_uv, tile->last_paintpos);
1515 
1516  /* Second check in pixel coordinates. */
1517  const float pixel_brush_size[] = {(s->symmetry & PAINT_TILE_X) ? FLT_MAX : size,
1518  (s->symmetry & PAINT_TILE_Y) ? FLT_MAX : size};
1519  if (!(is_inside_tile(tile->size, new_coord, pixel_brush_size) ||
1520  is_inside_tile(tile->size, old_coord, pixel_brush_size))) {
1521  continue;
1522  }
1523 
1524  ImBuf *ibuf = tile->canvas;
1525 
1526  /* OCIO_TODO: float buffers are now always linear, so always use color correction
1527  * this should probably be changed when texture painting color space is supported
1528  */
1530  painter->brush, tile, (ibuf->rect_float != NULL), !is_data, painter->cache_invert);
1531 
1532  brush_painter_2d_refresh_cache(s, painter, tile, new_coord, mval, pressure, distance, size);
1533 
1534  if (paint_2d_op(s, tile, old_coord, new_coord)) {
1535  tile->need_redraw = true;
1536  }
1537  }
1538 
1539  painter->firsttouch = false;
1540 }
1541 
1543 {
1545  SpaceImage *sima = CTX_wm_space_image(C);
1546  ToolSettings *settings = scene->toolsettings;
1547  Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
1548 
1549  ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
1550 
1551  s->sima = CTX_wm_space_image(C);
1552  s->v2d = &CTX_wm_region(C)->v2d;
1553  s->scene = scene;
1554 
1555  s->brush = brush;
1556  s->tool = brush->imagepaint_tool;
1557  s->blend = brush->blend;
1558 
1559  s->image = s->sima->image;
1560  s->symmetry = settings->imapaint.paint.symmetry_flags;
1561 
1562  if (s->image == NULL) {
1563  MEM_freeN(s);
1564  return NULL;
1565  }
1566  if (BKE_image_has_packedfile(s->image) && s->image->rr != NULL) {
1567  BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
1568  MEM_freeN(s);
1569  return NULL;
1570  }
1571 
1573  s->tiles = MEM_callocN(sizeof(ImagePaintTile) * s->num_tiles, "ImagePaintTile");
1574  for (int i = 0; i < s->num_tiles; i++) {
1575  s->tiles[i].iuser = sima->iuser;
1576  }
1577 
1578  zero_v2(s->tiles[0].uv_origin);
1579 
1580  ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[0].iuser, NULL);
1581  if (ibuf == NULL) {
1582  MEM_freeN(s->tiles);
1583  MEM_freeN(s);
1584  return NULL;
1585  }
1586 
1587  if (ibuf->channels != 4) {
1588  BKE_image_release_ibuf(s->image, ibuf, NULL);
1589  BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
1590  MEM_freeN(s->tiles);
1591  MEM_freeN(s);
1592  return NULL;
1593  }
1594 
1595  s->tiles[0].size[0] = ibuf->x;
1596  s->tiles[0].size[1] = ibuf->y;
1597  s->tiles[0].radius_fac = 1.0f;
1598 
1599  s->tiles[0].canvas = ibuf;
1600  s->tiles[0].state = PAINT2D_TILE_READY;
1601 
1602  /* Initialize offsets here, they're needed for the uv space clip test before lazy-loading the
1603  * tile properly. */
1604  int tile_idx = 0;
1605  for (ImageTile *tile = s->image->tiles.first; tile; tile = tile->next, tile_idx++) {
1606  s->tiles[tile_idx].iuser.tile = tile->tile_number;
1607  s->tiles[tile_idx].uv_origin[0] = ((tile->tile_number - 1001) % 10);
1608  s->tiles[tile_idx].uv_origin[1] = ((tile->tile_number - 1001) / 10);
1609  }
1610 
1611  if (!paint_2d_canvas_set(s)) {
1612  MEM_freeN(s->tiles);
1613 
1614  MEM_freeN(s);
1615  return NULL;
1616  }
1617 
1618  if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
1619  s->blurkernel = paint_new_blur_kernel(brush, false);
1620  }
1621 
1623 
1624  /* create painter */
1626 
1627  return s;
1628 }
1629 
1630 void paint_2d_redraw(const bContext *C, void *ps, bool final)
1631 {
1632  ImagePaintState *s = ps;
1633 
1634  bool had_redraw = false;
1635  for (int i = 0; i < s->num_tiles; i++) {
1636  if (s->tiles[i].need_redraw) {
1637  ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[i].iuser, NULL);
1638 
1639  imapaint_image_update(s->sima, s->image, ibuf, &s->tiles[i].iuser, false);
1640 
1641  BKE_image_release_ibuf(s->image, ibuf, NULL);
1642 
1643  s->tiles[i].need_redraw = false;
1644  had_redraw = true;
1645  }
1646  }
1647 
1648  if (had_redraw) {
1650  if (s->sima == NULL || !s->sima->lock) {
1652  }
1653  else {
1655  }
1656  }
1657 
1658  if (final) {
1659  if (s->image && !(s->sima && s->sima->lock)) {
1661  }
1662 
1663  /* compositor listener deals with updating */
1665  DEG_id_tag_update(&s->image->id, 0);
1666  }
1667 }
1668 
1669 void paint_2d_stroke_done(void *ps)
1670 {
1671  ImagePaintState *s = ps;
1672 
1674  for (int i = 0; i < s->num_tiles; i++) {
1676  }
1677  MEM_freeN(s->painter);
1678  MEM_freeN(s->tiles);
1680 
1681  MEM_freeN(s);
1682 }
1683 
1684 static void paint_2d_fill_add_pixel_byte(const int x_px,
1685  const int y_px,
1686  ImBuf *ibuf,
1687  BLI_Stack *stack,
1688  BLI_bitmap *touched,
1689  const float color[4],
1690  float threshold_sq)
1691 {
1692  size_t coordinate;
1693 
1694  if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0) {
1695  return;
1696  }
1697 
1698  coordinate = ((size_t)y_px) * ibuf->x + x_px;
1699 
1700  if (!BLI_BITMAP_TEST(touched, coordinate)) {
1701  float color_f[4];
1702  uchar *color_b = (uchar *)(ibuf->rect + coordinate);
1703  rgba_uchar_to_float(color_f, color_b);
1704  straight_to_premul_v4(color_f);
1705 
1706  if (len_squared_v4v4(color_f, color) <= threshold_sq) {
1707  BLI_stack_push(stack, &coordinate);
1708  }
1709  BLI_BITMAP_SET(touched, coordinate, true);
1710  }
1711 }
1712 
1713 static void paint_2d_fill_add_pixel_float(const int x_px,
1714  const int y_px,
1715  ImBuf *ibuf,
1716  BLI_Stack *stack,
1717  BLI_bitmap *touched,
1718  const float color[4],
1719  float threshold_sq)
1720 {
1721  size_t coordinate;
1722 
1723  if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0) {
1724  return;
1725  }
1726 
1727  coordinate = ((size_t)y_px) * ibuf->x + x_px;
1728 
1729  if (!BLI_BITMAP_TEST(touched, coordinate)) {
1730  if (len_squared_v4v4(ibuf->rect_float + 4 * coordinate, color) <= threshold_sq) {
1731  BLI_stack_push(stack, &coordinate);
1732  }
1733  BLI_BITMAP_SET(touched, coordinate, true);
1734  }
1735 }
1736 
1738 {
1739  ImageUser *iuser = &s->tiles[0].iuser;
1740  for (int i = 0; i < s->num_tiles; i++) {
1741  if (s->tiles[i].iuser.tile == tile_number) {
1742  if (!paint_2d_ensure_tile_canvas(s, i)) {
1743  return NULL;
1744  }
1745  iuser = &s->tiles[i].iuser;
1746  break;
1747  }
1748  }
1749 
1750  return iuser;
1751 }
1752 
1754  const float color[3],
1755  Brush *br,
1756  const float mouse_init[2],
1757  const float mouse_final[2],
1758  void *ps)
1759 {
1760  SpaceImage *sima = CTX_wm_space_image(C);
1761  Image *ima = sima->image;
1762 
1763  ImagePaintState *s = ps;
1764 
1765  ImBuf *ibuf;
1766  int x_px, y_px;
1767  uint color_b;
1768  float color_f[4];
1769  float strength = (s && br) ? BKE_brush_alpha_get(s->scene, br) : 1.0f;
1770 
1771  bool do_float;
1772 
1773  if (!ima) {
1774  return;
1775  }
1776 
1777  View2D *v2d = s ? s->v2d : &CTX_wm_region(C)->v2d;
1778  float uv_origin[2];
1779  float image_init[2];
1780  paint_2d_transform_mouse(v2d, mouse_init, image_init);
1781 
1782  int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin);
1783 
1784  ImageUser local_iuser, *iuser;
1785  if (s != NULL) {
1786  iuser = paint_2d_get_tile_iuser(s, tile_number);
1787  if (iuser == NULL) {
1788  return;
1789  }
1790  }
1791  else {
1792  iuser = &local_iuser;
1793  BKE_imageuser_default(iuser);
1794  iuser->tile = tile_number;
1795  }
1796 
1797  ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
1798  if (!ibuf) {
1799  return;
1800  }
1801 
1802  do_float = (ibuf->rect_float != NULL);
1803  /* first check if our image is float. If it is not we should correct the color to
1804  * be in gamma space. strictly speaking this is not correct, but blender does not paint
1805  * byte images in linear space */
1806  if (!do_float) {
1807  linearrgb_to_srgb_uchar3((uchar *)&color_b, color);
1808  *(((char *)&color_b) + 3) = strength * 255;
1809  }
1810  else {
1811  copy_v3_v3(color_f, color);
1812  color_f[3] = strength;
1813  }
1814 
1815  if (!mouse_final || !br) {
1816  /* first case, no image UV, fill the whole image */
1817  ED_imapaint_dirty_region(ima, ibuf, iuser, 0, 0, ibuf->x, ibuf->y, false);
1818 
1819  if (do_float) {
1820  for (x_px = 0; x_px < ibuf->x; x_px++) {
1821  for (y_px = 0; y_px < ibuf->y; y_px++) {
1822  blend_color_mix_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
1823  ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
1824  color_f);
1825  }
1826  }
1827  }
1828  else {
1829  for (x_px = 0; x_px < ibuf->x; x_px++) {
1830  for (y_px = 0; y_px < ibuf->y; y_px++) {
1831  blend_color_mix_byte((uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
1832  (uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
1833  (uchar *)&color_b);
1834  }
1835  }
1836  }
1837  }
1838  else {
1839  /* second case, start sweeping the neighboring pixels, looking for pixels whose
1840  * value is within the brush fill threshold from the fill color */
1841  BLI_Stack *stack;
1842  BLI_bitmap *touched;
1843  size_t coordinate;
1844  int width = ibuf->x;
1845  int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
1846  float pixel_color[4];
1847  /* We are comparing to sum of three squared values
1848  * (assumed in range [0,1]), so need to multiply... */
1849  float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
1850 
1851  x_px = image_init[0] * ibuf->x;
1852  y_px = image_init[1] * ibuf->y;
1853 
1854  if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
1855  BKE_image_release_ibuf(ima, ibuf, NULL);
1856  return;
1857  }
1858 
1859  /* change image invalidation method later */
1860  ED_imapaint_dirty_region(ima, ibuf, iuser, 0, 0, ibuf->x, ibuf->y, false);
1861 
1862  stack = BLI_stack_new(sizeof(size_t), __func__);
1863  touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
1864 
1865  coordinate = (((size_t)y_px) * ibuf->x + x_px);
1866 
1867  if (do_float) {
1868  copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
1869  }
1870  else {
1871  int pixel_color_b = *(ibuf->rect + coordinate);
1872  rgba_uchar_to_float(pixel_color, (uchar *)&pixel_color_b);
1873  straight_to_premul_v4(pixel_color);
1874  }
1875 
1876  BLI_stack_push(stack, &coordinate);
1877  BLI_BITMAP_SET(touched, coordinate, true);
1878 
1879  if (do_float) {
1880  while (!BLI_stack_is_empty(stack)) {
1881  BLI_stack_pop(stack, &coordinate);
1882 
1883  IMB_blend_color_float(ibuf->rect_float + 4 * (coordinate),
1884  ibuf->rect_float + 4 * (coordinate),
1885  color_f,
1886  br->blend);
1887 
1888  /* reconstruct the coordinates here */
1889  x_px = coordinate % width;
1890  y_px = coordinate / width;
1891 
1893  x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1895  x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1897  x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1899  x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1901  x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1903  x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1905  x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1907  x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1908 
1909  if (x_px > maxx) {
1910  maxx = x_px;
1911  }
1912  if (x_px < minx) {
1913  minx = x_px;
1914  }
1915  if (y_px > maxy) {
1916  maxy = y_px;
1917  }
1918  if (x_px > miny) {
1919  miny = y_px;
1920  }
1921  }
1922  }
1923  else {
1924  while (!BLI_stack_is_empty(stack)) {
1925  BLI_stack_pop(stack, &coordinate);
1926 
1927  IMB_blend_color_byte((uchar *)(ibuf->rect + coordinate),
1928  (uchar *)(ibuf->rect + coordinate),
1929  (uchar *)&color_b,
1930  br->blend);
1931 
1932  /* reconstruct the coordinates here */
1933  x_px = coordinate % width;
1934  y_px = coordinate / width;
1935 
1937  x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1939  x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1941  x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1943  x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1945  x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1947  x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1949  x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1951  x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1952 
1953  if (x_px > maxx) {
1954  maxx = x_px;
1955  }
1956  if (x_px < minx) {
1957  minx = x_px;
1958  }
1959  if (y_px > maxy) {
1960  maxy = y_px;
1961  }
1962  if (x_px > miny) {
1963  miny = y_px;
1964  }
1965  }
1966  }
1967 
1968  MEM_freeN(touched);
1969  BLI_stack_free(stack);
1970  }
1971 
1972  imapaint_image_update(sima, ima, ibuf, iuser, false);
1974 
1975  BKE_image_release_ibuf(ima, ibuf, NULL);
1976 
1978 }
1979 
1981  const bContext *C, Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps)
1982 {
1983  SpaceImage *sima = CTX_wm_space_image(C);
1984  Image *ima = sima->image;
1985  ImagePaintState *s = ps;
1986 
1987  ImBuf *ibuf;
1988  int x_px, y_px;
1989  uint color_b;
1990  float color_f[4];
1991  float image_init[2], image_final[2];
1992  float tangent[2];
1993  float line_len_sq_inv, line_len;
1994  const float brush_alpha = BKE_brush_alpha_get(s->scene, br);
1995 
1996  bool do_float;
1997 
1998  if (ima == NULL) {
1999  return;
2000  }
2001 
2002  float uv_origin[2];
2003  int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin);
2004  ImageUser *iuser = paint_2d_get_tile_iuser(s, tile_number);
2005  if (!iuser) {
2006  return;
2007  }
2008 
2009  ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
2010  if (ibuf == NULL) {
2011  return;
2012  }
2013 
2014  paint_2d_transform_mouse(s->v2d, mouse_final, image_final);
2015  paint_2d_transform_mouse(s->v2d, mouse_init, image_init);
2016  sub_v2_v2(image_init, uv_origin);
2017  sub_v2_v2(image_final, uv_origin);
2018 
2019  image_final[0] *= ibuf->x;
2020  image_final[1] *= ibuf->y;
2021 
2022  image_init[0] *= ibuf->x;
2023  image_init[1] *= ibuf->y;
2024 
2025  /* some math to get needed gradient variables */
2026  sub_v2_v2v2(tangent, image_final, image_init);
2027  line_len = len_squared_v2(tangent);
2028  line_len_sq_inv = 1.0f / line_len;
2029  line_len = sqrtf(line_len);
2030 
2031  do_float = (ibuf->rect_float != NULL);
2032 
2033  /* this will be substituted by something else when selection is available */
2034  ED_imapaint_dirty_region(ima, ibuf, iuser, 0, 0, ibuf->x, ibuf->y, false);
2035 
2036  if (do_float) {
2037  for (x_px = 0; x_px < ibuf->x; x_px++) {
2038  for (y_px = 0; y_px < ibuf->y; y_px++) {
2039  float f;
2040  const float p[2] = {x_px - image_init[0], y_px - image_init[1]};
2041 
2042  switch (br->gradient_fill_mode) {
2043  case BRUSH_GRADIENT_LINEAR: {
2044  f = dot_v2v2(p, tangent) * line_len_sq_inv;
2045  break;
2046  }
2047  case BRUSH_GRADIENT_RADIAL:
2048  default: {
2049  f = len_v2(p) / line_len;
2050  break;
2051  }
2052  }
2053  BKE_colorband_evaluate(br->gradient, f, color_f);
2054  /* convert to premultiplied */
2055  mul_v3_fl(color_f, color_f[3]);
2056  color_f[3] *= brush_alpha;
2057  IMB_blend_color_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
2058  ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
2059  color_f,
2060  br->blend);
2061  }
2062  }
2063  }
2064  else {
2065  for (x_px = 0; x_px < ibuf->x; x_px++) {
2066  for (y_px = 0; y_px < ibuf->y; y_px++) {
2067  float f;
2068  const float p[2] = {x_px - image_init[0], y_px - image_init[1]};
2069 
2070  switch (br->gradient_fill_mode) {
2071  case BRUSH_GRADIENT_LINEAR: {
2072  f = dot_v2v2(p, tangent) * line_len_sq_inv;
2073  break;
2074  }
2075  case BRUSH_GRADIENT_RADIAL:
2076  default: {
2077  f = len_v2(p) / line_len;
2078  break;
2079  }
2080  }
2081 
2082  BKE_colorband_evaluate(br->gradient, f, color_f);
2083  linearrgb_to_srgb_v3_v3(color_f, color_f);
2084  rgba_float_to_uchar((uchar *)&color_b, color_f);
2085  ((uchar *)&color_b)[3] *= brush_alpha;
2086  IMB_blend_color_byte((uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
2087  (uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
2088  (uchar *)&color_b,
2089  br->blend);
2090  }
2091  }
2092  }
2093 
2094  imapaint_image_update(sima, ima, ibuf, iuser, false);
2096 
2097  BKE_image_release_ibuf(ima, ibuf, NULL);
2098 
2100 }
typedef float(TangentPoint)[2]
float BKE_brush_sample_masktex(const struct Scene *scene, struct Brush *br, const float point[2], int thread, struct ImagePool *pool)
float BKE_brush_sample_tex_3d(const struct Scene *scene, const struct Brush *br, const float point[3], float rgba[4], int thread, struct ImagePool *pool)
float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush)
bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4])
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:824
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)
struct ImagePool * BKE_image_pool_new(void)
void BKE_image_free_gputextures(struct Image *ima)
Definition: image_gpu.cc:516
bool BKE_image_has_packedfile(const struct Image *image)
int BKE_image_get_tile_from_pos(struct Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
void BKE_imageuser_default(struct ImageUser *iuser)
void BKE_image_pool_free(struct ImagePool *pool)
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:607
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_SET(_bitmap, _index, _set)
Definition: BLI_bitmap.h:102
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int min_ii(int a, int b)
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
MINLINE void straight_to_premul_v4(float color[4])
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 linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
MINLINE void linearrgb_to_srgb_uchar3(unsigned char srgb[3], const float linear[3])
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
Definition: math_color.c:391
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2])
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v4(float r[4])
MINLINE float len_squared_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL()
Definition: stack.c:135
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition: stack.c:129
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:247
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition: stack.c:94
#define BLI_stack_new(esize, descr)
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
unsigned short ushort
Definition: BLI_sys_types.h:68
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define UNUSED(x)
#define MAX2(a, b)
#define ELEM(...)
void DEG_id_tag_update(struct ID *id, int flag)
@ BRUSH_ACCUMULATE
@ BRUSH_DIR_IN
@ BRUSH_ANCHORED
@ BRUSH_USE_GRADIENT
@ BRUSH_GRADIENT_SPACING_CLAMP
@ BRUSH_GRADIENT_SPACING_REPEAT
@ PAINT_TOOL_CLONE
@ PAINT_TOOL_SMEAR
@ PAINT_TOOL_SOFTEN
@ PAINT_TOOL_DRAW
@ BRUSH_GRADIENT_LINEAR
@ BRUSH_GRADIENT_RADIAL
Object is a sort of wrapper for general info.
@ PAINT_TILE_Y
@ PAINT_TILE_X
#define MTEX_MAP_MODE_VIEW
#define MTEX_MAP_MODE_3D
#define MTEX_MAP_MODE_STENCIL
#define MTEX_MAP_MODE_RANDOM
void ED_imapaint_clear_partial_redraw(void)
Definition: paint_image.cc:91
#define ED_IMAGE_UNDO_TILE_SIZE
Definition: ED_paint.h:105
void * ED_image_paint_tile_find(PaintTileMap *paint_tile_map, struct Image *image, struct ImBuf *ibuf, struct ImageUser *iuser, int x_tile, int y_tile, unsigned short **r_mask, bool validate)
Definition: image_undo.cc:158
struct PaintTileMap * ED_image_paint_tile_map_get(void)
Definition: image_undo.cc:1061
void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, struct ImageUser *iuser, int x, int y, int w, int h, bool find_old)
Definition: paint_image.cc:109
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble y1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_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 GLsizei width
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], struct ColorManagedDisplay *display)
struct ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
void IMB_float_from_rect(struct ImBuf *ibuf)
Definition: divers.c:805
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
void IMB_rectclip(struct ImBuf *dbuf, const struct ImBuf *sbuf, int *destx, int *desty, int *srcx, int *srcy, int *width, int *height)
void IMB_rect_from_float(struct ImBuf *ibuf)
Definition: divers.c:696
void IMB_rectblend_threaded(struct ImBuf *dbuf, const struct ImBuf *obuf, const struct ImBuf *sbuf, unsigned short *dmask, const unsigned short *curvemask, const unsigned short *texmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate)
void IMB_rectblend(struct ImBuf *dbuf, const struct ImBuf *obuf, const struct ImBuf *sbuf, unsigned short *dmask, const unsigned short *curvemask, const unsigned short *texmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, IMB_BlendMode mode, bool accumulate)
bool IMB_initImBuf(struct ImBuf *ibuf, unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:516
void IMB_blend_color_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], IMB_BlendMode mode)
Definition: rectop.c:24
@ IMB_BLEND_ERASE_ALPHA
Definition: IMB_imbuf.h:216
@ IMB_BLEND_COPY_RGB
Definition: IMB_imbuf.h:237
@ IMB_BLEND_COPY_ALPHA
Definition: IMB_imbuf.h:238
@ IMB_BLEND_COPY
Definition: IMB_imbuf.h:236
@ IMB_BLEND_INTERPOLATE
Definition: IMB_imbuf.h:234
void IMB_blend_color_float(float dst[4], const float src1[4], const float src2[4], IMB_BlendMode mode)
Definition: rectop.c:112
Contains defines and structs used throughout the imbuf module.
@ IMB_COLORMANAGE_IS_DATA
@ IB_rectfloat
@ IB_rect
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
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
#define C
Definition: RandGen.cpp:25
void UI_view2d_view_to_region_fl(const struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL()
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define NA_EDITED
Definition: WM_types.h:523
#define NC_IMAGE
Definition: WM_types.h:334
#define NA_PAINTING
Definition: WM_types.h:530
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
ListBase tiles
struct RenderResult * rr
Definition: thread.h:34
Scene scene
SyclQueue void void size_t num_bytes SyclQueue void const char void *memory_device_pointer KernelContext int kernel
uint pos
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
int count
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition: invert.h:8
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_global const KernelWorkTile * tile
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
const int state
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define floorf(x)
Definition: metal/compat.h:224
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned a[3]
Definition: RandGen.cpp:78
T distance(const T &a, const T &b)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken rgba("rgba", pxr::TfToken::Immortal)
static const pxr::TfToken rgb("rgb", pxr::TfToken::Immortal)
void paint_delete_blur_kernel(BlurKernel *kernel)
Definition: paint_image.cc:240
BlurKernel * paint_new_blur_kernel(Brush *br, bool proj)
Definition: paint_image.cc:171
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
Definition: paint_image.cc:144
void paint_brush_init_tex(Brush *brush)
Definition: paint_image.cc:374
bool paint_use_opacity_masking(Brush *brush)
Definition: paint_image.cc:317
void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display)
Definition: paint_image.cc:332
void paint_brush_exit_tex(Brush *brush)
Definition: paint_image.cc:390
void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
Definition: paint_image.cc:96
static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf, short paint_tile)
static void brush_painter_mask_imbuf_update(BrushPainter *painter, ImagePaintTile *tile, const ushort *tex_mask_old, int origx, int origy, int w, int h, int xt, int yt, const int diameter)
static void paint_2d_fill_add_pixel_float(const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched, const float color[4], float threshold_sq)
struct ImagePaintRegion ImagePaintRegion
static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short paint_tile, float w)
static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
ImagePaintTileState
@ PAINT2D_TILE_READY
@ PAINT2D_TILE_MISSING
@ PAINT2D_TILE_UNINITIALIZED
static void paint_2d_canvas_free(ImagePaintState *s)
struct BrushPainter BrushPainter
static void brush_painter_cache_2d_free(BrushPainterCache *cache)
static int paint_2d_op(void *state, ImagePaintTile *tile, const float lastpos[2], const float pos[2])
static ImBuf * brush_painter_imbuf_new(BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance)
static ImBuf * paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, const int *pos)
static void paint_2d_lift_soften(ImagePaintState *s, ImagePaintTile *tile, ImBuf *ibuf, ImBuf *ibufb, const int *pos, const short paint_tile)
static ImageUser * paint_2d_get_tile_iuser(ImagePaintState *s, int tile_number)
struct BrushPainterCache BrushPainterCache
static void paint_2d_do_making_brush(ImagePaintState *s, ImagePaintTile *tile, ImagePaintRegion *region, ImBuf *frombuf, float mask_max, short blend, int tilex, int tiley, int tilew, int tileh)
void paint_2d_bucket_fill(const bContext *C, const float color[3], Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps)
void paint_2d_gradient_fill(const bContext *C, Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps)
static void brush_painter_imbuf_partial_update(BrushPainter *painter, ImagePaintTile *tile, const float pos[2], const int diameter)
void paint_2d_stroke_done(void *ps)
static ushort * brush_painter_mask_ibuf_new(BrushPainter *painter, const int size)
static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
static bool paint_2d_ensure_tile_canvas(ImagePaintState *s, int i)
static BrushPainter * brush_painter_2d_new(Scene *scene, Brush *brush, bool invert)
struct Paint2DForeachData Paint2DForeachData
static void brush_painter_2d_tex_mapping(ImagePaintState *s, ImagePaintTile *tile, const int diameter, const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
static void paint_2d_transform_mouse(View2D *v2d, const float in[2], float out[2])
static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short paint_tile)
void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float base_size)
void * paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
static void paint_2d_uv_to_coord(ImagePaintTile *tile, const float uv[2], float coord[2])
static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, ImagePaintTile *tile, const float pos[2], const int diameter)
struct ImagePaintState ImagePaintState
static void paint_2d_op_foreach_do(void *__restrict data_v, const int iter, const TaskParallelTLS *__restrict UNUSED(tls))
static void brush_painter_2d_require_imbuf(Brush *brush, ImagePaintTile *tile, bool use_float, bool use_color_correction, bool invert)
static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
static int paint_2d_canvas_set(ImagePaintState *s)
static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short paint_tile)
void paint_2d_redraw(const bContext *C, void *ps, bool final)
struct ImagePaintTile ImagePaintTile
static bool is_inside_tile(const int size[2], const float pos[2], const float brush[2])
static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, ImagePaintTile *tile, const float pos[2], const float mouse[2], float pressure, float distance, float size)
static void brush_painter_imbuf_update(BrushPainter *painter, ImagePaintTile *tile, ImBuf *oldtexibuf, int origx, int origy, int w, int h, int xt, int yt)
static void paint_2d_fill_add_pixel_byte(const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched, const float color[4], float threshold_sq)
void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache)
void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, const Brush *brush, const int diameter, const float radius, const float cursor_position[2])
@ BRUSH_STROKE_INVERT
Definition: paint_intern.h:450
static void image_init(Image *ima, short source, short type)
struct Image * image
float offset[2]
CurveMaskCache curve_mask_cache
struct ImagePool * pool
struct ColorBand * gradient
struct BrushClone clone
struct MTex mtex
float sharp_threshold
float fill_threshold
char gradient_fill_mode
char imagepaint_tool
short blend
char gradient_stroke_mode
struct MTex mask_mtex
int mask_pressure
Caching structure for curve mask.
Definition: paint_intern.h:287
int channels
int colormanage_flag
unsigned char planes
unsigned int * rect
float * rect_float
ImagePaintTile * tiles
BlurKernel * blurkernel
SpaceImage * sima
BrushPainter * painter
BrushPainterCache cache
ImagePaintTileState state
float last_paintpos[2]
float uv_origin[2]
float start_paintpos[2]
void * first
Definition: DNA_listBase.h:31
char brush_map_mode
float rot
struct Tex * tex
ImagePaintTile * tile
ImagePaintRegion * region
ImagePaintState * s
int symmetry_flags
struct ToolSettings * toolsettings
ColorManagedDisplaySettings display_settings
struct ImageUser iuser
struct Image * image
struct ImagePaintSettings imapaint
struct UnifiedPaintSettings unified_paint_settings
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
struct ReportList * reports
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479