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