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