Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / sculpt_paint / paint_image_2d.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/sculpt_paint/paint_image_2d.c
29  *  \ingroup bke
30  */
31 //#include <math.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_brush_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_space_types.h"
39 #include "DNA_object_types.h"
40
41
42 #include "BLI_math_color_blend.h"
43 #include "BLI_stack.h"
44 #include "BLI_bitmap.h"
45 #include "BLI_task.h"
46
47 #include "BKE_colorband.h"
48 #include "BKE_context.h"
49 #include "BKE_brush.h"
50 #include "BKE_image.h"
51 #include "BKE_paint.h"
52 #include "BKE_report.h"
53
54 #include "DEG_depsgraph.h"
55
56 #include "ED_paint.h"
57 #include "ED_screen.h"
58
59 #include "IMB_imbuf.h"
60 #include "IMB_imbuf_types.h"
61 #include "IMB_colormanagement.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "UI_view2d.h"
67
68
69 #include "GPU_draw.h"
70
71 #include "paint_intern.h"
72
73 /* Brush Painting for 2D image editor */
74
75 /* Defines and Structs */
76
77 typedef struct BrushPainterCache {
78         bool use_float;              /* need float imbuf? */
79         bool use_color_correction;   /* use color correction for float */
80         bool invert;
81
82         bool is_texbrush;
83         bool is_maskbrush;
84
85         int lastdiameter;
86         float last_tex_rotation;
87         float last_mask_rotation;
88         float last_pressure;
89
90         ImBuf *ibuf;
91         ImBuf *texibuf;
92         unsigned short *curve_mask;
93         unsigned short *tex_mask;
94         unsigned short *tex_mask_old;
95         unsigned int tex_mask_old_w;
96         unsigned int tex_mask_old_h;
97 } BrushPainterCache;
98
99 typedef struct BrushPainter {
100         Scene *scene;
101         Brush *brush;
102
103         float lastpaintpos[2];  /* position of last paint op */
104         float startpaintpos[2]; /* position of first paint */
105
106         short firsttouch;       /* first paint op */
107
108         struct ImagePool *pool; /* image pool */
109         rctf tex_mapping;               /* texture coordinate mapping */
110         rctf mask_mapping;              /* mask texture coordinate mapping */
111
112         BrushPainterCache cache;
113 } BrushPainter;
114
115 typedef struct ImagePaintRegion {
116         int destx, desty;
117         int srcx, srcy;
118         int width, height;
119 } ImagePaintRegion;
120
121 typedef struct ImagePaintState {
122         BrushPainter *painter;
123         SpaceImage *sima;
124         View2D *v2d;
125         Scene *scene;
126         bScreen *screen;
127         struct ImagePool *image_pool;
128
129         Brush *brush;
130         short tool, blend;
131         Image *image;
132         ImBuf *canvas;
133         ImBuf *clonecanvas;
134         const char *warnpackedfile;
135         const char *warnmultifile;
136
137         bool do_masking;
138
139         /* viewport texture paint only, but _not_ project paint */
140         Object *ob;
141         int faceindex;
142         float uv[2];
143         int do_facesel;
144         int symmetry;
145
146         bool need_redraw;
147
148         BlurKernel *blurkernel;
149 } ImagePaintState;
150
151
152 static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool invert)
153 {
154         BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
155
156         painter->brush = brush;
157         painter->scene = scene;
158         painter->firsttouch = 1;
159         painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
160         painter->cache.invert = invert;
161
162         return painter;
163 }
164
165
166 static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction)
167 {
168         Brush *brush = painter->brush;
169
170         if ((painter->cache.use_float != use_float)) {
171                 if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
172                 if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
173                 if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
174                 if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
175                 painter->cache.ibuf = NULL;
176                 painter->cache.curve_mask = NULL;
177                 painter->cache.tex_mask = NULL;
178                 painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
179         }
180
181         painter->cache.use_float = use_float;
182         painter->cache.use_color_correction = use_float && use_color_correction;
183         painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
184         painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
185 }
186
187 static void brush_painter_2d_free(BrushPainter *painter)
188 {
189         if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
190         if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
191         if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
192         if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
193         if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
194         MEM_freeN(painter);
195 }
196
197 static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
198 {
199         texco[0] = mapping->xmin + x * mapping->xmax;
200         texco[1] = mapping->ymin + y * mapping->ymax;
201         texco[2] = 0.0f;
202 }
203
204 /* create a mask with the mask texture */
205 static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size)
206 {
207         Scene *scene = painter->scene;
208         Brush *brush = painter->brush;
209         rctf mask_mapping = painter->mask_mapping;
210         struct ImagePool *pool = painter->pool;
211
212         float texco[3];
213         unsigned short *mask, *m;
214         int x, y, thread = 0;
215
216         mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
217         m = mask;
218
219         for (y = 0; y < size; y++) {
220                 for (x = 0; x < size; x++, m++) {
221                         float res;
222                         brush_imbuf_tex_co(&mask_mapping, x, y, texco);
223                         res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
224                         *m = (unsigned short)(65535.0f * res);
225                 }
226         }
227
228         return mask;
229 }
230
231 /* update rectangular section of the brush image */
232 static void brush_painter_mask_imbuf_update(
233         BrushPainter *painter, unsigned short *tex_mask_old,
234         int origx, int origy, int w, int h, int xt, int yt, int diameter)
235 {
236         Scene *scene = painter->scene;
237         Brush *brush = painter->brush;
238         rctf tex_mapping = painter->mask_mapping;
239         struct ImagePool *pool = painter->pool;
240         unsigned short res;
241
242         bool use_texture_old = (tex_mask_old != NULL);
243
244         int x, y, thread = 0;
245
246         unsigned short *tex_mask = painter->cache.tex_mask;
247         unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
248
249         /* fill pixels */
250         for (y = origy; y < h; y++) {
251                 for (x = origx; x < w; x++) {
252                         /* sample texture */
253                         float texco[3];
254
255                         /* handle byte pixel */
256                         unsigned short *b = tex_mask + (y * diameter + x);
257                         unsigned short *t = tex_mask_cur + (y * diameter + x);
258
259                         if (!use_texture_old) {
260                                 brush_imbuf_tex_co(&tex_mapping, x, y, texco);
261                                 res = (unsigned short)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
262                         }
263
264                         /* read from old texture buffer */
265                         if (use_texture_old) {
266                                 res = *(tex_mask_old + ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt)));
267                         }
268
269                         /* write to new texture mask */
270                         *t = res;
271                         /* write to mask image buffer */
272                         *b = res;
273                 }
274         }
275 }
276
277
278 /**
279  * Update the brush mask image by trying to reuse the cached texture result.
280  * This can be considerably faster for brushes that change size due to pressure or
281  * textures that stick to the surface where only part of the pixels are new
282  */
283 static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
284 {
285         BrushPainterCache *cache = &painter->cache;
286         unsigned short *tex_mask_old;
287         int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
288
289         /* create brush image buffer if it didn't exist yet */
290         if (!cache->tex_mask)
291                 cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
292
293         /* create new texture image buffer with coordinates relative to old */
294         tex_mask_old = cache->tex_mask_old;
295         cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
296
297         if (tex_mask_old) {
298                 ImBuf maskibuf;
299                 ImBuf maskibuf_old;
300                 maskibuf.x = maskibuf.y = diameter;
301                 maskibuf_old.x = cache->tex_mask_old_w;
302                 maskibuf_old.y = cache->tex_mask_old_h;
303
304                 srcx = srcy = 0;
305                 w = cache->tex_mask_old_w;
306                 h = cache->tex_mask_old_h;
307                 destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0])  + (diameter / 2 - w / 2);
308                 desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1])  + (diameter / 2 - h / 2);
309
310                 /* hack, use temporary rects so that clipping works */
311                 IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
312         }
313         else {
314                 srcx = srcy = 0;
315                 destx = desty = 0;
316                 w = h = 0;
317         }
318
319         x1 = min_ii(destx, diameter);
320         y1 = min_ii(desty, diameter);
321         x2 = min_ii(destx + w, diameter);
322         y2 = min_ii(desty + h, diameter);
323
324         /* blend existing texture in new position */
325         if ((x1 < x2) && (y1 < y2))
326                 brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
327
328         if (tex_mask_old)
329                 MEM_freeN(tex_mask_old);
330
331         /* sample texture in new areas */
332         if ((0 < x1) && (0 < diameter))
333                 brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
334         if ((x2 < diameter) && (0 < diameter))
335                 brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
336         if ((x1 < x2) && (0 < y1))
337                 brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
338         if ((x1 < x2) && (y2 < diameter))
339                 brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);
340
341         /* through with sampling, now update sizes */
342         cache->tex_mask_old_w = diameter;
343         cache->tex_mask_old_h = diameter;
344 }
345
346 /* create a mask with the falloff strength */
347 static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, float radius)
348 {
349         Brush *brush = painter->brush;
350
351         int xoff = -radius;
352         int yoff = -radius;
353
354         unsigned short *mask, *m;
355         int x, y;
356
357         mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
358         m = mask;
359
360         for (y = 0; y < diameter; y++) {
361                 for (x = 0; x < diameter; x++, m++) {
362                         float xy[2] = {x + xoff, y + yoff};
363                         float len = len_v2(xy);
364
365                         *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
366                 }
367         }
368
369         return mask;
370 }
371
372
373 /* create imbuf with brush color */
374 static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance)
375 {
376         Scene *scene = painter->scene;
377         Brush *brush = painter->brush;
378
379         const char *display_device = scene->display_settings.display_device;
380         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
381
382         rctf tex_mapping = painter->tex_mapping;
383         struct ImagePool *pool = painter->pool;
384
385         bool use_color_correction = painter->cache.use_color_correction;
386         bool use_float = painter->cache.use_float;
387         bool is_texbrush = painter->cache.is_texbrush;
388
389         int x, y, thread = 0;
390         float brush_rgb[3];
391
392         /* allocate image buffer */
393         ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect);
394
395         /* get brush color */
396         if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
397                 paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display);
398         }
399         else {
400                 brush_rgb[0] = 1.0f;
401                 brush_rgb[1] = 1.0f;
402                 brush_rgb[2] = 1.0f;
403         }
404
405         /* fill image buffer */
406         for (y = 0; y < size; y++) {
407                 for (x = 0; x < size; x++) {
408                         /* sample texture and multiply with brush color */
409                         float texco[3], rgba[4];
410
411                         if (is_texbrush) {
412                                 brush_imbuf_tex_co(&tex_mapping, x, y, texco);
413                                 BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
414                                 /* TODO(sergey): Support texture paint color space. */
415                                 if (!use_float) {
416                                         IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
417                                 }
418                                 mul_v3_v3(rgba, brush_rgb);
419                         }
420                         else {
421                                 copy_v3_v3(rgba, brush_rgb);
422                                 rgba[3] = 1.0f;
423                         }
424
425                         if (use_float) {
426                                 /* write to float pixel */
427                                 float *dstf = ibuf->rect_float + (y * size + x) * 4;
428                                 mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */
429                                 dstf[3] = rgba[3];
430                         }
431                         else {
432                                 /* write to byte pixel */
433                                 unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;
434
435                                 rgb_float_to_uchar(dst, rgba);
436                                 dst[3] = unit_float_to_uchar_clamp(rgba[3]);
437                         }
438                 }
439         }
440
441         return ibuf;
442 }
443
444 /* update rectangular section of the brush image */
445 static void brush_painter_imbuf_update(
446         BrushPainter *painter, ImBuf *oldtexibuf,
447         int origx, int origy, int w, int h, int xt, int yt)
448 {
449         Scene *scene = painter->scene;
450         Brush *brush = painter->brush;
451
452         const char *display_device = scene->display_settings.display_device;
453         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
454
455         rctf tex_mapping = painter->tex_mapping;
456         struct ImagePool *pool = painter->pool;
457
458         bool use_color_correction = painter->cache.use_color_correction;
459         bool use_float = painter->cache.use_float;
460         bool is_texbrush = painter->cache.is_texbrush;
461         bool use_texture_old = (oldtexibuf != NULL);
462
463         int x, y, thread = 0;
464         float brush_rgb[3];
465
466         ImBuf *ibuf = painter->cache.ibuf;
467         ImBuf *texibuf = painter->cache.texibuf;
468
469         /* get brush color */
470         if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
471                 paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, 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) {
491                                                 IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
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 + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
509                                         copy_v4_v4(rgba, otf);
510                                 }
511
512                                 /* write to new texture buffer */
513                                 copy_v4_v4(tf, rgba);
514
515                                 /* output premultiplied float image, mf was already premultiplied */
516                                 mul_v3_v3fl(bf, rgba, rgba[3]);
517                                 bf[3] = rgba[3];
518                         }
519                         else {
520                                 unsigned char crgba[4];
521
522                                 /* handle byte pixel */
523                                 unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4;
524                                 unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4;
525
526                                 /* read from old texture buffer */
527                                 if (use_texture_old) {
528                                         unsigned char *ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
529                                         crgba[0] = ot[0];
530                                         crgba[1] = ot[1];
531                                         crgba[2] = ot[2];
532                                         crgba[3] = ot[3];
533                                 }
534                                 else
535                                         rgba_float_to_uchar(crgba, rgba);
536
537                                 /* write to new texture buffer */
538                                 t[0] = crgba[0];
539                                 t[1] = crgba[1];
540                                 t[2] = crgba[2];
541                                 t[3] = crgba[3];
542
543                                 /* write to brush image buffer */
544                                 b[0] = crgba[0];
545                                 b[1] = crgba[1];
546                                 b[2] = crgba[2];
547                                 b[3] = crgba[3];
548                         }
549                 }
550         }
551 }
552
553 /* update the brush image by trying to reuse the cached texture result. this
554  * can be considerably faster for brushes that change size due to pressure or
555  * textures that stick to the surface where only part of the pixels are new */
556 static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
557 {
558         BrushPainterCache *cache = &painter->cache;
559         ImBuf *oldtexibuf, *ibuf;
560         int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
561
562         /* create brush image buffer if it didn't exist yet */
563         imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
564         if (!cache->ibuf)
565                 cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
566         ibuf = cache->ibuf;
567
568         /* create new texture image buffer with coordinates relative to old */
569         oldtexibuf = cache->texibuf;
570         cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
571
572         if (oldtexibuf) {
573                 srcx = srcy = 0;
574                 w = oldtexibuf->x;
575                 h = oldtexibuf->y;
576                 destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
577                 desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
578
579                 IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
580         }
581         else {
582                 srcx = srcy = 0;
583                 destx = desty = 0;
584                 w = h = 0;
585         }
586
587         x1 = min_ii(destx, ibuf->x);
588         y1 = min_ii(desty, ibuf->y);
589         x2 = min_ii(destx + w, ibuf->x);
590         y2 = min_ii(desty + h, ibuf->y);
591
592         /* blend existing texture in new position */
593         if ((x1 < x2) && (y1 < y2))
594                 brush_painter_imbuf_update(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
595
596         if (oldtexibuf)
597                 IMB_freeImBuf(oldtexibuf);
598
599         /* sample texture in new areas */
600         if ((0 < x1) && (0 < ibuf->y))
601                 brush_painter_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
602         if ((x2 < ibuf->x) && (0 < ibuf->y))
603                 brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
604         if ((x1 < x2) && (0 < y1))
605                 brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
606         if ((x1 < x2) && (y2 < ibuf->y))
607                 brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
608 }
609
610 static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
611 {
612         float invw = 1.0f / (float)s->canvas->x;
613         float invh = 1.0f / (float)s->canvas->y;
614         int xmin, ymin, xmax, ymax;
615         int ipos[2];
616
617         /* find start coordinate of brush in canvas */
618         ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
619         ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
620
621         if (mapmode == MTEX_MAP_MODE_STENCIL) {
622                 /* map from view coordinates of brush to region coordinates */
623                 UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
624                 UI_view2d_view_to_region(s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
625
626                 /* output mapping from brush ibuf x/y to region coordinates */
627                 mapping->xmin = xmin;
628                 mapping->ymin = ymin;
629                 mapping->xmax = (xmax - xmin) / (float)diameter;
630                 mapping->ymax = (ymax - ymin) / (float)diameter;
631         }
632         else if (mapmode == MTEX_MAP_MODE_3D) {
633                 /* 3D mapping, just mapping to canvas 0..1  */
634                 mapping->xmin = 2.0f * (ipos[0] * invw - 0.5f);
635                 mapping->ymin = 2.0f * (ipos[1] * invh - 0.5f);
636                 mapping->xmax = 2.0f * invw;
637                 mapping->ymax = 2.0f * invh;
638         }
639         else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
640                 /* view mapping */
641                 mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
642                 mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
643                 mapping->xmax = 1.0f;
644                 mapping->ymax = 1.0f;
645         }
646         else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
647                 mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
648                 mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
649                 mapping->xmax = 1.0f;
650                 mapping->ymax = 1.0f;
651         }
652 }
653
654 static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2], float pressure, float distance, float size)
655 {
656         const Scene *scene = painter->scene;
657         UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
658         Brush *brush = painter->brush;
659         BrushPainterCache *cache = &painter->cache;
660         const int diameter = 2 * size;
661
662         bool do_random = false;
663         bool do_partial_update = false;
664         bool update_color = (
665                 (brush->flag & BRUSH_USE_GRADIENT) &&
666                 ((ELEM(brush->gradient_stroke_mode,
667                        BRUSH_GRADIENT_SPACING_REPEAT,
668                        BRUSH_GRADIENT_SPACING_CLAMP)) ||
669                  (cache->last_pressure != pressure)));
670         float tex_rotation = -brush->mtex.rot;
671         float mask_rotation = -brush->mask_mtex.rot;
672
673         painter->pool = BKE_image_pool_new();
674
675         /* determine how can update based on textures used */
676         if (painter->cache.is_texbrush) {
677                 if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
678                         tex_rotation += ups->brush_rotation;
679                 }
680                 else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
681                         do_random = true;
682                 else if (!((brush->flag & BRUSH_ANCHORED) || update_color))
683                         do_partial_update = true;
684
685                 brush_painter_2d_tex_mapping(
686                         s, diameter, painter->startpaintpos, pos, mouse,
687                         brush->mtex.brush_map_mode, &painter->tex_mapping);
688         }
689
690         if (painter->cache.is_maskbrush) {
691                 bool renew_maxmask = false;
692                 bool do_partial_update_mask = false;
693                 /* invalidate case for all mapping modes */
694                 if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
695                         mask_rotation += ups->brush_rotation_sec;
696                 }
697                 else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
698                         renew_maxmask = true;
699                 }
700                 else if (!(brush->flag & BRUSH_ANCHORED)) {
701                         do_partial_update_mask = true;
702                         renew_maxmask = true;
703                 }
704                 /* explicilty disable partial update even if it has been enabled above */
705                 if (brush->mask_pressure) {
706                         do_partial_update_mask = false;
707                         renew_maxmask = true;
708                 }
709
710                 if ((diameter != cache->lastdiameter) ||
711                     (mask_rotation != cache->last_mask_rotation) ||
712                     renew_maxmask)
713                 {
714                         if (cache->tex_mask) {
715                                 MEM_freeN(cache->tex_mask);
716                                 cache->tex_mask = NULL;
717                         }
718
719                         brush_painter_2d_tex_mapping(
720                                 s, diameter, painter->startpaintpos, pos, mouse,
721                                 brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
722
723                         if (do_partial_update_mask)
724                                 brush_painter_mask_imbuf_partial_update(painter, pos, diameter);
725                         else
726                                 cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
727                         cache->last_mask_rotation = mask_rotation;
728                 }
729         }
730
731         /* curve mask can only change if the size changes */
732         if (diameter != cache->lastdiameter) {
733                 if (cache->curve_mask) {
734                         MEM_freeN(cache->curve_mask);
735                         cache->curve_mask = NULL;
736                 }
737
738                 cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
739         }
740
741         /* detect if we need to recreate image brush buffer */
742         if ((diameter != cache->lastdiameter) ||
743             (tex_rotation != cache->last_tex_rotation) ||
744             do_random ||
745             update_color)
746         {
747                 if (cache->ibuf) {
748                         IMB_freeImBuf(cache->ibuf);
749                         cache->ibuf = NULL;
750                 }
751
752                 if (do_partial_update) {
753                         /* do partial update of texture */
754                         brush_painter_imbuf_partial_update(painter, pos, diameter);
755                 }
756                 else {
757                         /* create brush from scratch */
758                         cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
759                 }
760
761                 cache->lastdiameter = diameter;
762                 cache->last_tex_rotation = tex_rotation;
763                 cache->last_pressure = pressure;
764         }
765         else if (do_partial_update) {
766                 /* do only partial update of texture */
767                 int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]);
768                 int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]);
769
770                 if ((dx != 0) || (dy != 0)) {
771                         brush_painter_imbuf_partial_update(painter, pos, diameter);
772                 }
773         }
774
775         BKE_image_pool_free(painter->pool);
776         painter->pool = NULL;
777 }
778
779 /* keep these functions in sync */
780 static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
781 {
782         if (ibuf->rect_float) {
783                 const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
784                 copy_v4_v4(r_rgb, rrgbf);
785         }
786         else {
787                 unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
788                 straight_uchar_to_premul_float(r_rgb, rrgb);
789         }
790 }
791 static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
792 {
793         if (is_torus) {
794                 x %= ibuf->x;
795                 if (x < 0) x += ibuf->x;
796                 y %= ibuf->y;
797                 if (y < 0) y += ibuf->y;
798         }
799
800         if (ibuf->rect_float) {
801                 float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
802                 float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];
803
804                 mul_v3_v3fl(rrgbf, rgb, map_alpha);
805                 rrgbf[3] = rgb[3];
806         }
807         else {
808                 unsigned char straight[4];
809                 unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
810
811                 premul_float_to_straight_uchar(straight, rgb);
812                 rrgb[0] = straight[0];
813                 rrgb[1] = straight[1];
814                 rrgb[2] = straight[2];
815                 rrgb[3] = straight[3];
816         }
817 }
818
819 static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
820 {
821         if (tile & PAINT_TILE_X) {
822                 *x %= ibuf->x;
823                 if (*x < 0) *x += ibuf->x;
824         }
825         if (tile & PAINT_TILE_Y) {
826                 *y %= ibuf->y;
827                 if (*y < 0) *y += ibuf->y;
828         }
829 }
830
831
832 static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
833 {
834         float inrgb[4];
835
836         if (tile) paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
837         /* need to also do clipping here always since tiled coordinates
838          * are not always within bounds */
839         if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
840                 paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
841         }
842         else return 0;
843
844         mul_v4_fl(inrgb, w);
845         add_v4_v4(outrgb, inrgb);
846
847         return w;
848 }
849
850 static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
851 {
852         bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
853         float threshold = s->brush->sharp_threshold;
854         int x, y, xi, yi, xo, yo, xk, yk;
855         float count;
856         int out_off[2], in_off[2], dim[2];
857         int diff_pos[2];
858         float outrgb[4];
859         float rgba[4];
860         BlurKernel *kernel = s->blurkernel;
861
862         dim[0] = ibufb->x;
863         dim[1] = ibufb->y;
864         in_off[0] = pos[0];
865         in_off[1] = pos[1];
866         out_off[0] = out_off[1] = 0;
867
868         if (!tile) {
869                 IMB_rectclip(
870                         ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
871                         &out_off[1], &dim[0], &dim[1]);
872
873                 if ((dim[0] == 0) || (dim[1] == 0))
874                         return;
875         }
876
877         /* find offset inside mask buffers to sample them */
878         sub_v2_v2v2_int(diff_pos, out_off, in_off);
879
880         for (y = 0; y < dim[1]; y++) {
881                 for (x = 0; x < dim[0]; x++) {
882                         /* get input pixel */
883                         xi = in_off[0] + x;
884                         yi = in_off[1] + y;
885
886                         count = 0.0;
887                         if (tile) {
888                                 paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
889                                 if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
890                                         paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
891                                 else
892                                         zero_v4(rgba);
893                         }
894                         else {
895                                 /* coordinates have been clipped properly here, it should be safe to do this */
896                                 paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
897                         }
898                         zero_v4(outrgb);
899
900                         for (yk = 0; yk < kernel->side; yk++) {
901                                 for (xk = 0; xk < kernel->side; xk++) {
902                                         count += paint_2d_ibuf_add_if(
903                                                 ibuf, xi + xk - kernel->pixel_len,
904                                                 yi + yk - kernel->pixel_len, outrgb, tile,
905                                                 kernel->wdata[xk + yk * kernel->side]);
906                                 }
907                         }
908
909                         if (count > 0.0f) {
910                                 mul_v4_fl(outrgb, 1.0f / (float)count);
911
912                                 if (sharpen) {
913                                         /* subtract blurred image from normal image gives high pass filter */
914                                         sub_v3_v3v3(outrgb, rgba, outrgb);
915
916                                         /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
917                                          * colored speckles appearing in final image, and also to check for threshold */
918                                         outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
919                                         if (fabsf(outrgb[0]) > threshold) {
920                                                 float mask = BKE_brush_alpha_get(s->scene, s->brush);
921                                                 float alpha = rgba[3];
922                                                 rgba[3] = outrgb[3] = mask;
923
924                                                 /* add to enhance edges */
925                                                 blend_color_add_float(outrgb, rgba, outrgb);
926                                                 outrgb[3] = alpha;
927                                         }
928                                         else
929                                                 copy_v4_v4(outrgb, rgba);
930                                 }
931                         }
932                         else
933                                 copy_v4_v4(outrgb, rgba);
934                         /* write into brush buffer */
935                         xo = out_off[0] + x;
936                         yo = out_off[1] + y;
937                         paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
938                 }
939         }
940 }
941
942 static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
943 {
944         region->destx = destx;
945         region->desty = desty;
946         region->srcx = srcx;
947         region->srcy = srcy;
948         region->width = width;
949         region->height = height;
950 }
951
952 static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf, short tile)
953 {
954         int destx = region->destx;
955         int desty = region->desty;
956         int srcx = region->srcx;
957         int srcy = region->srcy;
958         int width = region->width;
959         int height = region->height;
960         int origw, origh, w, h, tot = 0;
961
962         /* convert destination and source coordinates to be within image */
963         if (tile & PAINT_TILE_X) {
964                 destx = destx % dbuf->x;
965                 if (destx < 0) destx += dbuf->x;
966                 srcx = srcx % sbuf->x;
967                 if (srcx < 0) srcx += sbuf->x;
968         }
969         if (tile & PAINT_TILE_Y) {
970                 desty = desty % dbuf->y;
971                 if (desty < 0) desty += dbuf->y;
972                 srcy = srcy % sbuf->y;
973                 if (srcy < 0) srcy += sbuf->y;
974         }
975         /* clip width of blending area to destination imbuf, to avoid writing the
976          * same pixel twice */
977         origw = w = (width > dbuf->x) ? dbuf->x : width;
978         origh = h = (height > dbuf->y) ? dbuf->y : height;
979
980         /* clip within image */
981         IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
982         paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
983
984         /* do 3 other rects if needed */
985         if ((tile & PAINT_TILE_X) && w < origw)
986                 paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
987         if ((tile & PAINT_TILE_Y) && h < origh)
988                 paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
989         if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
990                 paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
991
992         return tot;
993 }
994
995 static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
996 {
997         ImagePaintRegion region[4];
998         int a, tot;
999
1000         paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
1001         tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
1002
1003         for (a = 0; a < tot; a++)
1004                 IMB_rectblend(
1005                         ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty,
1006                         region[a].destx, region[a].desty,
1007                         region[a].srcx, region[a].srcy,
1008                         region[a].width, region[a].height, IMB_BLEND_COPY, false);
1009 }
1010
1011 static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
1012 {
1013         /* note: allocImbuf returns zero'd memory, so regions outside image will
1014          * have zero alpha, and hence not be blended onto the image */
1015         int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
1016         ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
1017
1018         IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
1019         IMB_rectblend(
1020                 clonebuf, clonebuf, ibufb, NULL, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
1021                 IMB_BLEND_COPY_ALPHA, false);
1022         IMB_rectblend(
1023                 clonebuf, clonebuf, ibuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
1024                 IMB_BLEND_COPY_RGB, false);
1025
1026         return clonebuf;
1027 }
1028
1029 static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
1030 {
1031         ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
1032         ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
1033 }
1034
1035 static void paint_2d_do_making_brush(
1036         ImagePaintState *s,
1037         ImagePaintRegion *region,
1038         unsigned short *curveb,
1039         unsigned short *texmaskb,
1040         ImBuf *frombuf,
1041         float mask_max,
1042         short blend,
1043         int tilex, int tiley,
1044         int tilew, int tileh)
1045 {
1046         ImBuf tmpbuf;
1047         IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
1048
1049         ListBase *undo_tiles = ED_image_undo_get_tiles();
1050
1051         for (int ty = tiley; ty <= tileh; ty++) {
1052                 for (int tx = tilex; tx <= tilew; tx++) {
1053                         /* retrieve original pixels + mask from undo buffer */
1054                         unsigned short *mask;
1055                         int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
1056                         int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
1057
1058                         if (s->canvas->rect_float)
1059                                 tmpbuf.rect_float = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
1060                         else
1061                                 tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
1062
1063                         IMB_rectblend(
1064                                 s->canvas, &tmpbuf, frombuf, mask,
1065                                 curveb, texmaskb, mask_max,
1066                                 region->destx, region->desty,
1067                                 origx, origy,
1068                                 region->srcx, region->srcy,
1069                                 region->width, region->height,
1070                                 blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
1071                 }
1072         }
1073 }
1074
1075 typedef struct Paint2DForeachData {
1076         ImagePaintState *s;
1077         ImagePaintRegion *region;
1078         unsigned short *curveb;
1079         unsigned short *texmaskb;
1080         ImBuf *frombuf;
1081         float mask_max;
1082         short blend;
1083         int tilex;
1084         int tilew;
1085 } Paint2DForeachData;
1086
1087 static void paint_2d_op_foreach_do(
1088         void *__restrict data_v,
1089         const int iter,
1090         const ParallelRangeTLS *__restrict UNUSED(tls))
1091 {
1092         Paint2DForeachData *data = (Paint2DForeachData *)data_v;
1093         paint_2d_do_making_brush(
1094                 data->s, data->region, data->curveb,
1095                 data->texmaskb, data->frombuf, data->mask_max,
1096                 data->blend,
1097                 data->tilex, iter,
1098                 data->tilew, iter);
1099 }
1100
1101 static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
1102 {
1103         ImagePaintState *s = ((ImagePaintState *)state);
1104         ImBuf *clonebuf = NULL, *frombuf;
1105         ImagePaintRegion region[4];
1106         short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
1107         short blend = s->blend;
1108         const float *offset = s->brush->clone.offset;
1109         float liftpos[2];
1110         float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
1111         int bpos[2], blastpos[2], bliftpos[2];
1112         int a, tot;
1113
1114         paint_2d_convert_brushco(ibufb, pos, bpos);
1115
1116         /* lift from canvas */
1117         if (s->tool == PAINT_TOOL_SOFTEN) {
1118                 paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
1119                 blend = IMB_BLEND_INTERPOLATE;
1120         }
1121         else if (s->tool == PAINT_TOOL_SMEAR) {
1122                 if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
1123                         return 0;
1124
1125                 paint_2d_convert_brushco(ibufb, lastpos, blastpos);
1126                 paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
1127                 blend = IMB_BLEND_INTERPOLATE;
1128         }
1129         else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
1130                 liftpos[0] = pos[0] - offset[0] * s->canvas->x;
1131                 liftpos[1] = pos[1] - offset[1] * s->canvas->y;
1132
1133                 paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
1134                 clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
1135         }
1136
1137         frombuf = (clonebuf) ? clonebuf : ibufb;
1138
1139         if (tile) {
1140                 paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
1141                 tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
1142         }
1143         else {
1144                 paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
1145                 tot = 1;
1146         }
1147
1148         /* blend into canvas */
1149         for (a = 0; a < tot; a++) {
1150                 ED_imapaint_dirty_region(
1151                         s->image, s->canvas,
1152                         region[a].destx, region[a].desty,
1153                         region[a].width, region[a].height, true);
1154
1155                 if (s->do_masking) {
1156                         /* masking, find original pixels tiles from undo buffer to composite over */
1157                         int tilex, tiley, tilew, tileh;
1158
1159                         imapaint_region_tiles(
1160                                 s->canvas, region[a].destx, region[a].desty,
1161                                 region[a].width, region[a].height,
1162                                 &tilex, &tiley, &tilew, &tileh);
1163
1164                         if (tiley == tileh) {
1165                                 paint_2d_do_making_brush(
1166                                         s, &region[a], curveb, texmaskb, frombuf,
1167                                         mask_max, blend, tilex, tiley, tilew, tileh);
1168                         }
1169                         else {
1170                                 Paint2DForeachData data;
1171                                 data.s = s;
1172                                 data.region = &region[a];
1173                                 data.curveb = curveb;
1174                                 data.texmaskb = texmaskb;
1175                                 data.frombuf = frombuf;
1176                                 data.mask_max = mask_max;
1177                                 data.blend = blend;
1178                                 data.tilex = tilex;
1179                                 data.tilew = tilew;
1180
1181                                 ParallelRangeSettings settings;
1182                                 BLI_parallel_range_settings_defaults(&settings);
1183                                 BLI_task_parallel_range(
1184                                         tiley, tileh + 1, &data,
1185                                         paint_2d_op_foreach_do,
1186                                         &settings);
1187
1188                         }
1189                 }
1190                 else {
1191                         /* no masking, composite brush directly onto canvas */
1192                         IMB_rectblend_threaded(
1193                                 s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max,
1194                                 region[a].destx, region[a].desty,
1195                                 region[a].destx, region[a].desty,
1196                                 region[a].srcx, region[a].srcy,
1197                                 region[a].width, region[a].height, blend, false);
1198                 }
1199         }
1200
1201         if (clonebuf) IMB_freeImBuf(clonebuf);
1202
1203         return 1;
1204 }
1205
1206
1207 static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
1208 {
1209         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
1210
1211         /* verify that we can paint and set canvas */
1212         if (ima == NULL) {
1213                 return 0;
1214         }
1215         else if (BKE_image_has_packedfile(ima) && ima->rr) {
1216                 s->warnpackedfile = ima->id.name + 2;
1217                 return 0;
1218         }
1219         else if (ibuf && ibuf->channels != 4) {
1220                 s->warnmultifile = ima->id.name + 2;
1221                 return 0;
1222         }
1223         else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
1224                 return 0;
1225
1226         s->image = ima;
1227         s->canvas = ibuf;
1228
1229         /* set clone canvas */
1230         if (s->tool == PAINT_TOOL_CLONE) {
1231                 ima = s->brush->clone.image;
1232                 ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
1233
1234                 if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
1235                         BKE_image_release_ibuf(ima, ibuf, NULL);
1236                         BKE_image_release_ibuf(s->image, s->canvas, NULL);
1237                         return 0;
1238                 }
1239
1240                 s->clonecanvas = ibuf;
1241
1242                 /* temporarily add float rect for cloning */
1243                 if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
1244                         IMB_float_from_rect(s->clonecanvas);
1245                 }
1246                 else if (!s->canvas->rect_float && !s->clonecanvas->rect)
1247                         IMB_rect_from_float(s->clonecanvas);
1248         }
1249
1250         /* set masking */
1251         s->do_masking = paint_use_opacity_masking(s->brush);
1252
1253         return 1;
1254 }
1255
1256 static void paint_2d_canvas_free(ImagePaintState *s)
1257 {
1258         BKE_image_release_ibuf(s->image, s->canvas, NULL);
1259         BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
1260
1261         if (s->blurkernel) {
1262                 paint_delete_blur_kernel(s->blurkernel);
1263                 MEM_freeN(s->blurkernel);
1264         }
1265
1266         image_undo_remove_masks();
1267 }
1268
1269 void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size)
1270 {
1271         float newuv[2], olduv[2];
1272         ImagePaintState *s = ps;
1273         BrushPainter *painter = s->painter;
1274         ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
1275         const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA);
1276
1277         if (!ibuf)
1278                 return;
1279
1280         s->blend = s->brush->blend;
1281         if (eraser)
1282                 s->blend = IMB_BLEND_ERASE_ALPHA;
1283
1284         UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
1285         UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]);
1286
1287         newuv[0] *= ibuf->x;
1288         newuv[1] *= ibuf->y;
1289
1290         olduv[0] *= ibuf->x;
1291         olduv[1] *= ibuf->y;
1292
1293         if (painter->firsttouch) {
1294                 float startuv[2];
1295
1296                 UI_view2d_region_to_view(s->v2d, 0, 0, &startuv[0], &startuv[1]);
1297
1298                 /* paint exactly once on first touch */
1299                 painter->startpaintpos[0] = startuv[0] * ibuf->x;
1300                 painter->startpaintpos[1] = startuv[1] * ibuf->y;
1301
1302                 painter->firsttouch = 0;
1303                 copy_v2_v2(painter->lastpaintpos, newuv);
1304         }
1305         else {
1306                 copy_v2_v2(painter->lastpaintpos, olduv);
1307         }
1308
1309         /* OCIO_TODO: float buffers are now always linear, so always use color correction
1310          *            this should probably be changed when texture painting color space is supported
1311          */
1312         brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data);
1313
1314         brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
1315
1316         if (paint_2d_op(s, painter->cache.ibuf, painter->cache.curve_mask, painter->cache.tex_mask, olduv, newuv))
1317                 s->need_redraw = true;
1318
1319         BKE_image_release_ibuf(s->image, ibuf, NULL);
1320 }
1321
1322 void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
1323 {
1324         Scene *scene = CTX_data_scene(C);
1325         ToolSettings *settings = scene->toolsettings;
1326         Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
1327
1328         ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
1329
1330         s->sima = CTX_wm_space_image(C);
1331         s->v2d = &CTX_wm_region(C)->v2d;
1332         s->scene = scene;
1333         s->screen = CTX_wm_screen(C);
1334
1335         s->brush = brush;
1336         s->tool = brush->imagepaint_tool;
1337         s->blend = brush->blend;
1338
1339         s->image = s->sima->image;
1340         s->symmetry = settings->imapaint.paint.symmetry_flags;
1341
1342         if (!paint_2d_canvas_set(s, s->image)) {
1343                 if (s->warnmultifile)
1344                         BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
1345                 if (s->warnpackedfile)
1346                         BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
1347
1348                 MEM_freeN(s);
1349                 return NULL;
1350         }
1351
1352         if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
1353                 s->blurkernel = paint_new_blur_kernel(brush, false);
1354         }
1355
1356         paint_brush_init_tex(s->brush);
1357
1358         /* create painter */
1359         s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT);
1360
1361         return s;
1362 }
1363
1364 void paint_2d_redraw(const bContext *C, void *ps, bool final)
1365 {
1366         ImagePaintState *s = ps;
1367
1368         if (s->need_redraw) {
1369                 ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
1370
1371                 imapaint_image_update(s->sima, s->image, ibuf, false);
1372                 ED_imapaint_clear_partial_redraw();
1373
1374                 BKE_image_release_ibuf(s->image, ibuf, NULL);
1375
1376                 s->need_redraw = false;
1377         }
1378         else if (!final) {
1379                 return;
1380         }
1381
1382         if (final) {
1383                 if (s->image && !(s->sima && s->sima->lock))
1384                         GPU_free_image(s->image);
1385
1386                 /* compositor listener deals with updating */
1387                 WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
1388                 DEG_id_tag_update(&s->image->id, 0);
1389         }
1390         else {
1391                 if (!s->sima || !s->sima->lock)
1392                         ED_region_tag_redraw(CTX_wm_region(C));
1393                 else
1394                         WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
1395         }
1396 }
1397
1398 void paint_2d_stroke_done(void *ps)
1399 {
1400         ImagePaintState *s = ps;
1401
1402         paint_2d_canvas_free(s);
1403         brush_painter_2d_free(s->painter);
1404         paint_brush_exit_tex(s->brush);
1405
1406         MEM_freeN(s);
1407 }
1408
1409 static void paint_2d_fill_add_pixel_byte(
1410         const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
1411         const float color[4], float threshold_sq)
1412 {
1413         size_t coordinate;
1414
1415         if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
1416                 return;
1417
1418         coordinate = ((size_t)y_px) * ibuf->x + x_px;
1419
1420         if (!BLI_BITMAP_TEST(touched, coordinate)) {
1421                 float color_f[4];
1422                 unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
1423                 rgba_uchar_to_float(color_f, color_b);
1424
1425                 if (compare_len_squared_v3v3(color_f, color, threshold_sq)) {
1426                         BLI_stack_push(stack, &coordinate);
1427                 }
1428                 BLI_BITMAP_SET(touched, coordinate, true);
1429         }
1430 }
1431
1432 static void paint_2d_fill_add_pixel_float(
1433         const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
1434         const float color[4], float threshold_sq)
1435 {
1436         size_t coordinate;
1437
1438         if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
1439                 return;
1440
1441         coordinate = ((size_t)y_px) * ibuf->x + x_px;
1442
1443         if (!BLI_BITMAP_TEST(touched, coordinate)) {
1444                 if (compare_len_squared_v3v3(ibuf->rect_float + 4 * coordinate, color, threshold_sq)) {
1445                         BLI_stack_push(stack, &coordinate);
1446                 }
1447                 BLI_BITMAP_SET(touched, coordinate, true);
1448         }
1449 }
1450
1451 /* this function expects linear space color values */
1452 void paint_2d_bucket_fill(
1453         const bContext *C, const float color[3], Brush *br,
1454         const float mouse_init[2],
1455         void *ps)
1456 {
1457         SpaceImage *sima = CTX_wm_space_image(C);
1458         Image *ima = sima->image;
1459
1460         ImagePaintState *s = ps;
1461
1462         ImBuf *ibuf;
1463         int x_px, y_px;
1464         unsigned int color_b;
1465         float color_f[4];
1466         float strength = br ? br->alpha : 1.0f;
1467
1468         bool do_float;
1469
1470         if (!ima)
1471                 return;
1472
1473         ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
1474
1475         if (!ibuf)
1476                 return;
1477
1478         do_float = (ibuf->rect_float != NULL);
1479         /* first check if our image is float. If it is not we should correct the color to
1480          * be in gamma space. strictly speaking this is not correct, but blender does not paint
1481          * byte images in linear space */
1482         if (!do_float) {
1483                 linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
1484                 *(((char *)&color_b) + 3) = strength * 255;
1485         }
1486         else {
1487                 copy_v3_v3(color_f, color);
1488                 color_f[3] = strength;
1489         }
1490
1491         if (!mouse_init || !br) {
1492                 /* first case, no image UV, fill the whole image */
1493                 ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
1494
1495                 if (do_float) {
1496                         for (x_px = 0; x_px < ibuf->x; x_px++) {
1497                                 for (y_px = 0; y_px < ibuf->y; y_px++) {
1498                                         blend_color_mix_float(
1499                                                 ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
1500                                                 ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px), color_f);
1501                                 }
1502                         }
1503                 }
1504                 else {
1505                         for (x_px = 0; x_px < ibuf->x; x_px++) {
1506                                 for (y_px = 0; y_px < ibuf->y; y_px++) {
1507                                         blend_color_mix_byte(
1508                                                 (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
1509                                                 (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px), (unsigned char *)&color_b);
1510                                 }
1511                         }
1512                 }
1513         }
1514         else {
1515                 /* second case, start sweeping the neighboring pixels, looking for pixels whose
1516                  * value is within the brush fill threshold from the fill color */
1517                 BLI_Stack *stack;
1518                 BLI_bitmap *touched;
1519                 size_t coordinate;
1520                 int width = ibuf->x;
1521                 float image_init[2];
1522                 int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
1523                 float pixel_color[4];
1524                 /* We are comparing to sum of three squared values (assumed in range [0,1]), so need to multiply... */
1525                 float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
1526
1527                 UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
1528
1529                 x_px = image_init[0] * ibuf->x;
1530                 y_px = image_init[1] * ibuf->y;
1531
1532                 if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
1533                         BKE_image_release_ibuf(ima, ibuf, NULL);
1534                         return;
1535                 }
1536
1537                 /* change image invalidation method later */
1538                 ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
1539
1540                 stack = BLI_stack_new(sizeof(size_t), __func__);
1541                 touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
1542
1543                 coordinate = (((size_t)y_px) * ibuf->x + x_px);
1544
1545                 if (do_float) {
1546                         copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
1547                 }
1548                 else {
1549                         int pixel_color_b = *(ibuf->rect + coordinate);
1550                         rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
1551                 }
1552
1553                 BLI_stack_push(stack, &coordinate);
1554                 BLI_BITMAP_SET(touched, coordinate, true);
1555
1556                 if (do_float) {
1557                         while (!BLI_stack_is_empty(stack)) {
1558                                 BLI_stack_pop(stack, &coordinate);
1559
1560                                 IMB_blend_color_float(
1561                                         ibuf->rect_float + 4 * (coordinate),
1562                                         ibuf->rect_float + 4 * (coordinate),
1563                                         color_f, br->blend);
1564
1565                                 /* reconstruct the coordinates here */
1566                                 x_px = coordinate % width;
1567                                 y_px = coordinate / width;
1568
1569                                 paint_2d_fill_add_pixel_float(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1570                                 paint_2d_fill_add_pixel_float(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1571                                 paint_2d_fill_add_pixel_float(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1572                                 paint_2d_fill_add_pixel_float(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1573                                 paint_2d_fill_add_pixel_float(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1574                                 paint_2d_fill_add_pixel_float(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1575                                 paint_2d_fill_add_pixel_float(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1576                                 paint_2d_fill_add_pixel_float(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1577
1578                                 if (x_px > maxx)
1579                                         maxx = x_px;
1580                                 if (x_px < minx)
1581                                         minx = x_px;
1582                                 if (y_px > maxy)
1583                                         maxy = y_px;
1584                                 if (x_px > miny)
1585                                         miny = y_px;
1586                         }
1587                 }
1588                 else {
1589                         while (!BLI_stack_is_empty(stack)) {
1590                                 BLI_stack_pop(stack, &coordinate);
1591
1592                                 IMB_blend_color_byte(
1593                                         (unsigned char *)(ibuf->rect + coordinate),
1594                                         (unsigned char *)(ibuf->rect + coordinate),
1595                                         (unsigned char *)&color_b, br->blend);
1596
1597                                 /* reconstruct the coordinates here */
1598                                 x_px = coordinate % width;
1599                                 y_px = coordinate / width;
1600
1601                                 paint_2d_fill_add_pixel_byte(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1602                                 paint_2d_fill_add_pixel_byte(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1603                                 paint_2d_fill_add_pixel_byte(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1604                                 paint_2d_fill_add_pixel_byte(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1605                                 paint_2d_fill_add_pixel_byte(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1606                                 paint_2d_fill_add_pixel_byte(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
1607                                 paint_2d_fill_add_pixel_byte(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
1608                                 paint_2d_fill_add_pixel_byte(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
1609
1610                                 if (x_px > maxx)
1611                                         maxx = x_px;
1612                                 if (x_px < minx)
1613                                         minx = x_px;
1614                                 if (y_px > maxy)
1615                                         maxy = y_px;
1616                                 if (x_px > miny)
1617                                         miny = y_px;
1618                         }
1619                 }
1620
1621                 MEM_freeN(touched);
1622                 BLI_stack_free(stack);
1623         }
1624
1625         imapaint_image_update(sima, ima, ibuf, false);
1626         ED_imapaint_clear_partial_redraw();
1627
1628         BKE_image_release_ibuf(ima, ibuf, NULL);
1629
1630         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1631 }
1632
1633 void paint_2d_gradient_fill(
1634         const bContext *C, Brush *br,
1635         const float mouse_init[2], const float mouse_final[2],
1636         void *ps)
1637 {
1638         SpaceImage *sima = CTX_wm_space_image(C);
1639         Image *ima = sima->image;
1640         ImagePaintState *s = ps;
1641
1642         ImBuf *ibuf;
1643         int x_px, y_px;
1644         unsigned int color_b;
1645         float color_f[4];
1646         float image_init[2], image_final[2];
1647         float tangent[2];
1648         float line_len_sq_inv, line_len;
1649
1650         bool do_float;
1651
1652         if (!ima)
1653                 return;
1654
1655         ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
1656
1657         if (!ibuf)
1658                 return;
1659
1660         UI_view2d_region_to_view(s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
1661         UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
1662
1663         image_final[0] *= ibuf->x;
1664         image_final[1] *= ibuf->y;
1665
1666         image_init[0] *= ibuf->x;
1667         image_init[1] *= ibuf->y;
1668
1669         /* some math to get needed gradient variables */
1670         sub_v2_v2v2(tangent, image_final, image_init);
1671         line_len = len_squared_v2(tangent);
1672         line_len_sq_inv = 1.0f / line_len;
1673         line_len = sqrtf(line_len);
1674
1675         do_float = (ibuf->rect_float != NULL);
1676
1677         /* this will be substituted by something else when selection is available */
1678         ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
1679
1680         if (do_float) {
1681                 for (x_px = 0; x_px < ibuf->x; x_px++) {
1682                         for (y_px = 0; y_px < ibuf->y; y_px++) {
1683                                 float f;
1684                                 float p[2] = {x_px - image_init[0], y_px - image_init[1]};
1685
1686                                 switch (br->gradient_fill_mode) {
1687                                         case BRUSH_GRADIENT_LINEAR:
1688                                         {
1689                                                 f = dot_v2v2(p, tangent) * line_len_sq_inv;
1690                                                 break;
1691                                         }
1692                                         case BRUSH_GRADIENT_RADIAL:
1693                                         default:
1694                                         {
1695                                                 f = len_v2(p) / line_len;
1696                                                 break;
1697                                         }
1698                                 }
1699                                 BKE_colorband_evaluate(br->gradient, f, color_f);
1700                                 /* convert to premultiplied */
1701                                 mul_v3_fl(color_f, color_f[3]);
1702                                 color_f[3] *= br->alpha;
1703                                 IMB_blend_color_float(
1704                                         ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
1705                                         ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
1706                                         color_f, br->blend);
1707                         }
1708                 }
1709         }
1710         else {
1711                 for (x_px = 0; x_px < ibuf->x; x_px++) {
1712                         for (y_px = 0; y_px < ibuf->y; y_px++) {
1713                                 float f;
1714                                 float p[2] = {x_px - image_init[0], y_px - image_init[1]};
1715
1716                                 switch (br->gradient_fill_mode) {
1717                                         case BRUSH_GRADIENT_LINEAR:
1718                                         {
1719                                                 f = dot_v2v2(p, tangent) * line_len_sq_inv;
1720                                                 break;
1721                                         }
1722                                         case BRUSH_GRADIENT_RADIAL:
1723                                         default:
1724                                         {
1725                                                 f = len_v2(p) / line_len;
1726                                                 break;
1727                                         }
1728                                 }
1729
1730                                 BKE_colorband_evaluate(br->gradient, f, color_f);
1731                                 linearrgb_to_srgb_v3_v3(color_f, color_f);
1732                                 rgba_float_to_uchar((unsigned char *)&color_b, color_f);
1733                                 ((unsigned char *)&color_b)[3] *= br->alpha;
1734                                 IMB_blend_color_byte(
1735                                         (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
1736                                         (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
1737                                         (unsigned char *)&color_b, br->blend);
1738                         }
1739                 }
1740         }
1741
1742         imapaint_image_update(sima, ima, ibuf, false);
1743         ED_imapaint_clear_partial_redraw();
1744
1745         BKE_image_release_ibuf(ima, ibuf, NULL);
1746
1747         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1748 }