Blender V4.5
paint_image.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
10#include <cfloat>
11#include <cmath>
12#include <cstdio>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_listbase.h"
18#include "BLI_math_vector.hh"
19#include "BLI_noise.hh"
20#include "BLI_rand.hh"
21#include "BLI_string.h"
22#include "BLI_utildefines.h"
23
24#include "BLT_translation.hh"
25
26#include "IMB_imbuf.hh"
27#include "IMB_imbuf_types.hh"
28
29#include "DNA_brush_types.h"
30#include "DNA_material_types.h"
31#include "DNA_mesh_types.h"
32#include "DNA_node_types.h"
33#include "DNA_object_types.h"
34#include "DNA_scene_types.h"
35
36#include "BKE_brush.hh"
37#include "BKE_colorband.hh"
38#include "BKE_colortools.hh"
39#include "BKE_context.hh"
40#include "BKE_curves.hh"
41#include "BKE_grease_pencil.hh"
42#include "BKE_image.hh"
43#include "BKE_library.hh"
44#include "BKE_main.hh"
45#include "BKE_material.hh"
46#include "BKE_mesh.hh"
47#include "BKE_node_runtime.hh"
48#include "BKE_object.hh"
49#include "BKE_paint.hh"
50#include "BKE_report.hh"
51#include "BKE_scene.hh"
52
53#include "NOD_texture.h"
54
55#include "DEG_depsgraph.hh"
57
58#include "UI_interface.hh"
59#include "UI_view2d.hh"
60
61#include "ED_grease_pencil.hh"
62#include "ED_image.hh"
63#include "ED_object.hh"
64#include "ED_paint.hh"
65#include "ED_screen.hh"
66
67#include "WM_api.hh"
68#include "WM_message.hh"
69#include "WM_toolsystem.hh"
70#include "WM_types.hh"
71
72#include "RNA_access.hh"
73#include "RNA_define.hh"
74
76
77#include "paint_intern.hh"
78
79/* -------------------------------------------------------------------- */
82
89
94
99
100/* Image paint Partial Redraw & Dirty Region. */
101
106
108 ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
109{
110 int srcx = 0, srcy = 0;
111
112 IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
113
114 *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
115 *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
116 *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
117 *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
118}
119
121 Image *ima, ImBuf *ibuf, ImageUser *iuser, int x, int y, int w, int h, bool find_old)
122{
123 ImBuf *tmpibuf = nullptr;
124 int tilex, tiley, tilew, tileh, tx, ty;
125 int srcx = 0, srcy = 0;
126
127 IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
128
129 if (w == 0 || h == 0) {
130 return;
131 }
132
133 rcti rect_to_merge;
134 BLI_rcti_init(&rect_to_merge, x, x + w, y, y + h);
135 BLI_rcti_do_minmax_rcti(&imapaintpartial.dirty_region, &rect_to_merge);
136
137 imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
138
140
141 for (ty = tiley; ty <= tileh; ty++) {
142 for (tx = tilex; tx <= tilew; tx++) {
144 undo_tiles, ima, ibuf, &tmpibuf, iuser, tx, ty, nullptr, nullptr, false, find_old);
145 }
146 }
147
148 BKE_image_mark_dirty(ima, ibuf);
149
150 if (tmpibuf) {
151 IMB_freeImBuf(tmpibuf);
152 }
153}
154
156 SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
157{
158 if (BLI_rcti_is_empty(&imapaintpartial.dirty_region)) {
159 return;
160 }
161
162 if (ibuf->mipmap[0]) {
164 }
165
167 imapaintpartial.dirty_region.xmin,
168 imapaintpartial.dirty_region.ymin,
169 imapaintpartial.dirty_region.xmax,
170 imapaintpartial.dirty_region.ymax);
171
172 /* When buffer is partial updated the planes should be set to a larger value than 8. This will
173 * make sure that partial updating is working but uses more GPU memory as the gpu texture will
174 * have 4 channels. When so the whole texture needs to be re-uploaded to the GPU using the new
175 * texture format. */
176 if (ibuf != nullptr && ibuf->planes == 8) {
177 ibuf->planes = 32;
179 return;
180 }
181
182 /* TODO: should set_tpage create ->rect? */
183 if (texpaint || (sima && sima->lock)) {
184 const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region);
185 const int h = BLI_rcti_size_y(&imapaintpartial.dirty_region);
186 /* Testing with partial update in uv editor too. */
188 image, iuser, imapaintpartial.dirty_region.xmin, imapaintpartial.dirty_region.ymin, w, h);
189 }
190}
191
193
194/* -------------------------------------------------------------------- */
197
199{
200 int i, j;
201 BlurKernel *kernel = MEM_new<BlurKernel>("BlurKernel");
202
203 float radius;
204 int side;
205 eBlurKernelType type = static_cast<eBlurKernelType>(br->blur_mode);
206
207 if (proj) {
208 radius = 0.5f;
209
210 side = kernel->side = 2;
211 kernel->side_squared = kernel->side * kernel->side;
212 kernel->wdata = MEM_malloc_arrayN<float>(kernel->side_squared, "blur kernel data");
213 kernel->pixel_len = radius;
214 }
215 else {
216 if (br->blur_kernel_radius <= 0) {
217 br->blur_kernel_radius = 1;
218 }
219
220 radius = br->blur_kernel_radius;
221
222 side = kernel->side = radius * 2 + 1;
223 kernel->side_squared = kernel->side * kernel->side;
224 kernel->wdata = MEM_malloc_arrayN<float>(kernel->side_squared, "blur kernel data");
225 kernel->pixel_len = br->blur_kernel_radius;
226 }
227
228 switch (type) {
229 case KERNEL_BOX:
230 for (i = 0; i < kernel->side_squared; i++) {
231 kernel->wdata[i] = 1.0;
232 }
233 break;
234
235 case KERNEL_GAUSSIAN: {
236 /* at 3.0 standard deviations distance, kernel is about zero */
237 float standard_dev = radius / 3.0f;
238
239 /* make the necessary adjustment to the value for use in the normal distribution formula */
240 standard_dev = -standard_dev * standard_dev * 2;
241
242 for (i = 0; i < side; i++) {
243 for (j = 0; j < side; j++) {
244 float idist = radius - i;
245 float jdist = radius - j;
246 float value = exp((idist * idist + jdist * jdist) / standard_dev);
247
248 kernel->wdata[i + j * side] = value;
249 }
250 }
251
252 break;
253 }
254
255 default:
256 printf("unidentified kernel type, aborting\n");
258 MEM_delete(kernel);
259 return nullptr;
260 }
261
262 return kernel;
263}
264
266{
267 if (kernel->wdata) {
268 MEM_freeN(kernel->wdata);
269 }
270}
271
273
274/* -------------------------------------------------------------------- */
277
279{
280 Scene *scene = CTX_data_scene(C);
281 ToolSettings *settings = scene->toolsettings;
282
283 return BKE_paint_brush(&settings->imapaint.paint);
284}
285
286static bool image_paint_poll_ex(bContext *C, bool check_tool)
287{
288 Object *obact;
289
290 if (!image_paint_brush(C)) {
291 return false;
292 }
293
294 obact = CTX_data_active_object(C);
295 if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
296 if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
297 return true;
298 }
299 }
300 else {
302
303 if (sima) {
304 if (sima->image != nullptr &&
306 {
307 return false;
308 }
309 if (sima->mode == SI_MODE_PAINT) {
310 const ARegion *region = CTX_wm_region(C);
311 if (region->regiontype == RGN_TYPE_WINDOW) {
312 return true;
313 }
314 }
315 }
316 }
317
318 return false;
319}
320
322{
323 return image_paint_poll_ex(C, true);
324}
325
327{
328 return image_paint_poll_ex(C, false);
329}
330
332{
333 const Scene *scene = CTX_data_scene(C);
334 const ToolSettings *settings = scene->toolsettings;
335 const ImagePaintSettings &image_paint_settings = settings->imapaint;
336 Brush *brush = image_paint_brush(C);
337
339 if (brush && (brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_CLONE)) {
340 if (image_paint_settings.clone) {
341 return true;
342 }
343 }
344 }
345
346 return false;
347}
348
350
351/* -------------------------------------------------------------------- */
354
355bool paint_use_opacity_masking(const Scene *scene, const Paint *paint, const Brush *brush)
356{
357 return ((brush->flag & BRUSH_AIRBRUSH) || (brush->flag & BRUSH_DRAG_DOT) ||
358 (brush->flag & BRUSH_ANCHORED) ||
359 ELEM(brush->image_brush_type,
363 (brush->flag & BRUSH_USE_GRADIENT) ||
364 (BKE_brush_color_jitter_get_settings(scene, paint, brush)) ||
365 (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode,
369 false :
370 true);
371}
372
374 const Paint *paint,
375 Brush *br,
376 std::optional<blender::float3> &initial_hsv_jitter,
377 bool color_correction,
378 bool invert,
379 float distance,
380 float pressure,
381 const ColorManagedDisplay *display,
382 float r_color[3])
383{
384 if (invert) {
385 copy_v3_v3(r_color, BKE_brush_secondary_color_get(scene, paint, br));
386 }
387 else {
388 const std::optional<BrushColorJitterSettings> color_jitter_settings =
389 BKE_brush_color_jitter_get_settings(scene, paint, br);
390 if (br->flag & BRUSH_USE_GRADIENT) {
391 float color_gr[4];
392 switch (br->gradient_stroke_mode) {
394 BKE_colorband_evaluate(br->gradient, pressure, color_gr);
395 break;
397 float coord = fmod(distance / br->gradient_spacing, 1.0);
398 BKE_colorband_evaluate(br->gradient, coord, color_gr);
399 break;
400 }
403 break;
404 }
405 }
406 /* Gradient / Color-band colors are not considered #PROP_COLOR_GAMMA.
407 * Brush colors are expected to be in sRGB though. */
409 }
410 else if (color_jitter_settings) {
411 copy_v3_v3(r_color,
412 BKE_paint_randomize_color(*color_jitter_settings,
413 *initial_hsv_jitter,
414 distance,
415 pressure,
416 BKE_brush_color_get(scene, paint, br)));
417 }
418 else {
419 copy_v3_v3(r_color, BKE_brush_color_get(scene, paint, br));
420 }
421 }
422 if (color_correction) {
424 }
425}
426
428{
429 /* init mtex nodes */
430 if (brush) {
431 MTex *mtex = &brush->mtex;
432 if (mtex->tex && mtex->tex->nodetree) {
433 /* has internal flag to detect it only does it once */
435 }
436 mtex = &brush->mask_mtex;
437 if (mtex->tex && mtex->tex->nodetree) {
439 }
440 }
441}
442
444{
445 if (brush) {
446 MTex *mtex = &brush->mtex;
447 if (mtex->tex && mtex->tex->nodetree) {
448 ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
449 }
450 mtex = &brush->mask_mtex;
451 if (mtex->tex && mtex->tex->nodetree) {
452 ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
453 }
454 }
455}
456
457bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
458{
459 ScrArea *area = CTX_wm_area(C);
460 if (area && area->spacetype == SPACE_IMAGE) {
461 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
462 if (sima->mode == SI_MODE_PAINT) {
463 ARegion *region = CTX_wm_region(C);
464 ED_space_image_get_zoom(sima, region, zoomx, zoomy);
465 return true;
466 }
467 }
468
469 *zoomx = *zoomy = 1;
470
471 return false;
472}
473
475
476/* -------------------------------------------------------------------- */
479
480static void toggle_paint_cursor(Scene &scene, bool enable)
481{
482 ToolSettings *settings = scene.toolsettings;
483 Paint &p = settings->imapaint.paint;
484
485 if (p.paint_cursor && !enable) {
487 p.paint_cursor = nullptr;
489 }
490 else if (enable) {
492 }
493}
494
496{
497 ToolSettings *settings = scene->toolsettings;
498 ImagePaintSettings *imapaint = &settings->imapaint;
499 bool enabled = false;
500
501 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
503
504 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
505 if (area->spacetype == SPACE_IMAGE) {
506 if (((SpaceImage *)area->spacedata.first)->mode == SI_MODE_PAINT) {
507 enabled = true;
508 }
509 }
510 }
511 }
512
513 if (enabled) {
515
517 }
518 else {
520 }
521}
522
524
525/* -------------------------------------------------------------------- */
528
529struct GrabClone {
530 float startoffset[2];
532};
533
535{
536 const Scene *scene = CTX_data_scene(C);
537 ToolSettings *settings = scene->toolsettings;
538 ImagePaintSettings &image_paint_settings = settings->imapaint;
539 float delta[2];
540
541 RNA_float_get_array(op->ptr, "delta", delta);
542 add_v2_v2(image_paint_settings.clone_offset, delta);
544}
545
552
554{
555 const Scene *scene = CTX_data_scene(C);
556 const ToolSettings *settings = scene->toolsettings;
557 const ImagePaintSettings &image_paint_settings = settings->imapaint;
558 GrabClone *cmv;
559
560 cmv = MEM_callocN<GrabClone>("GrabClone");
561 copy_v2_v2(cmv->startoffset, image_paint_settings.clone_offset);
562 cmv->startx = event->xy[0];
563 cmv->starty = event->xy[1];
564 op->customdata = cmv;
565
567
569}
570
572{
573 const Scene *scene = CTX_data_scene(C);
574 ToolSettings *settings = scene->toolsettings;
575 ImagePaintSettings &image_paint_settings = settings->imapaint;
576 ARegion *region = CTX_wm_region(C);
577 GrabClone *cmv = static_cast<GrabClone *>(op->customdata);
578 float startfx, startfy, fx, fy, delta[2];
579 int xmin = region->winrct.xmin, ymin = region->winrct.ymin;
580
581 switch (event->type) {
582 case LEFTMOUSE:
583 case MIDDLEMOUSE:
584 case RIGHTMOUSE: /* XXX hardcoded */
585 MEM_freeN(cmv);
586 return OPERATOR_FINISHED;
587 case MOUSEMOVE:
588 /* mouse moved, so move the clone image */
590 &region->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy);
591 UI_view2d_region_to_view(&region->v2d, event->xy[0] - xmin, event->xy[1] - ymin, &fx, &fy);
592
593 delta[0] = fx - startfx;
594 delta[1] = fy - startfy;
595 RNA_float_set_array(op->ptr, "delta", delta);
596
597 copy_v2_v2(image_paint_settings.clone_offset, cmv->startoffset);
598
599 grab_clone_apply(C, op);
600 break;
601 default: {
602 break;
603 }
604 }
605
607}
608
609static void grab_clone_cancel(bContext * /*C*/, wmOperator *op)
610{
611 GrabClone *cmv = static_cast<GrabClone *>(op->customdata);
612 MEM_delete(cmv);
613}
614
616{
617 /* identifiers */
618 ot->name = "Grab Clone";
619 ot->idname = "PAINT_OT_grab_clone";
620 ot->description = "Move the clone source image";
621
622 /* API callbacks. */
623 ot->exec = grab_clone_exec;
624 ot->invoke = grab_clone_invoke;
625 ot->modal = grab_clone_modal;
626 ot->cancel = grab_clone_cancel;
628
629 /* flags */
631
632 /* properties */
634 "delta",
635 2,
636 nullptr,
637 -FLT_MAX,
638 FLT_MAX,
639 "Delta",
640 "Delta offset of clone image in 0.0 to 1.0 coordinates",
641 -1.0f,
642 1.0f);
643}
644
646
647/* -------------------------------------------------------------------- */
650
657
659{
660 char msg[UI_MAX_DRAW_STR];
661 ScrArea *area = CTX_wm_area(C);
662
663 if (area) {
664 SNPRINTF(msg,
665 IFACE_("Sample color for %s"),
666 !data->sample_palette ?
667 IFACE_("Brush. Use Left Click to sample for palette instead") :
668 IFACE_("Palette. Use Left Click to sample more colors"));
670 }
671}
672
674{
676 Brush *brush = BKE_paint_brush(paint);
678 ARegion *region = CTX_wm_region(C);
679 wmWindow *win = CTX_wm_window(C);
680 const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
681 int location[2];
682 paint->flags &= ~PAINT_SHOW_BRUSH;
683
684 /* force redraw without cursor */
685 WM_paint_cursor_tag_redraw(win, region);
687
688 RNA_int_get_array(op->ptr, "location", location);
689 const bool use_palette = RNA_boolean_get(op->ptr, "palette");
690 const bool use_sample_texture = (mode == PaintMode::Texture3D) &&
691 !RNA_boolean_get(op->ptr, "merged");
692
693 paint_sample_color(C, region, location[0], location[1], use_sample_texture, use_palette);
694
695 if (show_cursor) {
696 paint->flags |= PAINT_SHOW_BRUSH;
697 }
698
700
701 return OPERATOR_FINISHED;
702}
703
705{
706 Scene *scene = CTX_data_scene(C);
708 Brush *brush = BKE_paint_brush(paint);
709 SampleColorData *data = MEM_new<SampleColorData>("sample color custom data");
710 ARegion *region = CTX_wm_region(C);
711 wmWindow *win = CTX_wm_window(C);
712
713 data->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
714 data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
715 copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, paint, brush));
716 data->sample_palette = false;
717 op->customdata = data;
718 paint->flags &= ~PAINT_SHOW_BRUSH;
719
721
723
724 /* force redraw without cursor */
725 WM_paint_cursor_tag_redraw(win, region);
727
728 RNA_int_set_array(op->ptr, "location", event->mval);
729
731 const bool use_sample_texture = (mode == PaintMode::Texture3D) &&
732 !RNA_boolean_get(op->ptr, "merged");
733
734 paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, false);
736
738
740}
741
743{
744 Scene *scene = CTX_data_scene(C);
745 SampleColorData *data = static_cast<SampleColorData *>(op->customdata);
747 Brush *brush = BKE_paint_brush(paint);
748
749 if ((event->type == data->launch_event) && (event->val == KM_RELEASE)) {
750 if (data->show_cursor) {
751 paint->flags |= PAINT_SHOW_BRUSH;
752 }
753
754 if (data->sample_palette) {
755 BKE_brush_color_set(scene, paint, brush, data->initcolor);
756 RNA_boolean_set(op->ptr, "palette", true);
758 }
760 MEM_delete(data);
761 ED_workspace_status_text(C, nullptr);
762
763 return OPERATOR_FINISHED;
764 }
765
767 const bool use_sample_texture = (mode == PaintMode::Texture3D) &&
768 !RNA_boolean_get(op->ptr, "merged");
769
770 switch (event->type) {
771 case MOUSEMOVE: {
772 ARegion *region = CTX_wm_region(C);
773 RNA_int_set_array(op->ptr, "location", event->mval);
774 paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, false);
776 break;
777 }
778
779 case LEFTMOUSE:
780 if (event->val == KM_PRESS) {
781 ARegion *region = CTX_wm_region(C);
782 RNA_int_set_array(op->ptr, "location", event->mval);
783 paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, true);
784 if (!data->sample_palette) {
785 data->sample_palette = true;
787 BKE_report(op->reports, RPT_INFO, "Sampling color for palette");
788 }
790 }
791 break;
792 default: {
793 break;
794 }
795 }
796
798}
799
805
807{
808 /* identifiers */
809 ot->name = "Sample Color";
810 ot->idname = "PAINT_OT_sample_color";
811 ot->description = "Use the mouse to sample a color in the image";
812
813 /* API callbacks. */
814 ot->exec = sample_color_exec;
815 ot->invoke = sample_color_invoke;
816 ot->modal = sample_color_modal;
817 ot->poll = sample_color_poll;
818
819 /* flags */
821
822 /* properties */
823 PropertyRNA *prop;
824
825 prop = RNA_def_int_vector(
826 ot->srna, "location", 2, nullptr, 0, INT_MAX, "Location", "", 0, 16384);
828
829 RNA_def_boolean(ot->srna, "merged", false, "Sample Merged", "Sample the output display color");
830 RNA_def_boolean(ot->srna, "palette", false, "Add to Palette", "");
831}
832
834
835/* -------------------------------------------------------------------- */
838
840{
841 using namespace blender;
842 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
843 if (!mesh_eval) {
844 mesh_eval = (const Mesh *)ob->data;
845 }
846
847 const std::optional<Bounds<float3>> bounds = mesh_eval->bounds_min_max();
848 if (!bounds) {
849 return float3(0.0f);
850 }
851
852 return math::midpoint(bounds->min, bounds->max);
853}
854
856{
857 const Curves &curves = *static_cast<const Curves *>(ob->data);
858 const std::optional<blender::Bounds<blender::float3>> bounds =
859 curves.geometry.wrap().bounds_min_max();
860 if (bounds.has_value()) {
861 return blender::math::midpoint(bounds->min, bounds->max);
862 }
863 return blender::float3(0);
864}
865
867{
868 using namespace blender;
869 const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(ob->data);
870 const std::optional<Bounds<float3>> bounds = grease_pencil.bounds_min_max(frame);
871 if (bounds.has_value()) {
872 return blender::math::midpoint(bounds->min, bounds->max);
873 }
874 return float3(0.0f);
875}
876
878{
880
881 blender::float3 location;
882 switch (ob->type) {
883 case OB_MESH:
884 location = paint_init_pivot_mesh(ob);
885 break;
886 case OB_CURVES:
887 location = paint_init_pivot_curves(ob);
888 break;
889 case OB_GREASE_PENCIL:
890 location = paint_init_pivot_grease_pencil(ob, scene->r.cfra);
891 break;
892 default:
894 ups->last_stroke_valid = false;
895 return;
896 }
897
898 mul_m4_v3(ob->object_to_world().ptr(), location);
899
900 ups->last_stroke_valid = true;
901 ups->average_stroke_counter = 1;
902 copy_v3_v3(ups->average_stroke_accum, location);
903}
904
906 Scene &scene,
907 Depsgraph &depsgraph,
908 Object &ob)
909{
910 Image *ima = nullptr;
911 ImagePaintSettings &imapaint = scene.toolsettings->imapaint;
912
913 /* This has to stay here to regenerate the texture paint
914 * cache in case we are loading a file */
916
917 ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
918
919 /* entering paint mode also sets image to editors */
920 if (imapaint.mode == IMAGEPAINT_MODE_MATERIAL) {
921 /* set the current material active paint slot on image editor */
923
924 if (ma && ma->texpaintslot) {
925 ima = ma->texpaintslot[ma->paint_active_slot].ima;
926 }
927 }
928 else if (imapaint.mode == IMAGEPAINT_MODE_IMAGE) {
929 ima = imapaint.canvas;
930 }
931
932 if (ima) {
933 ED_space_image_sync(&bmain, ima, false);
934 }
935
937
939
940 BKE_paint_brushes_validate(&bmain, &imapaint.paint);
941
942 if (U.glreslimit != 0) {
944 }
945 BKE_image_paint_set_mipmap(&bmain, false);
946
947 toggle_paint_cursor(scene, true);
948
949 Mesh *mesh = BKE_mesh_from_object(&ob);
950 BLI_assert(mesh != nullptr);
952
953 /* Ensure we have evaluated data for bounding box. */
955
956 /* Set pivot to bounding box center. */
957 Object *ob_eval = DEG_get_evaluated(&depsgraph, &ob);
958 paint_init_pivot(ob_eval ? ob_eval : &ob, &scene);
959
961}
962
972
974{
976
977 if (U.glreslimit != 0) {
979 }
980 BKE_image_paint_set_mipmap(&bmain, true);
981 toggle_paint_cursor(scene, false);
982
983 Mesh *mesh = BKE_mesh_from_object(&ob);
984 BLI_assert(mesh != nullptr);
987}
988
996
998{
1000 if (ob == nullptr || ob->type != OB_MESH) {
1001 return false;
1002 }
1003 if (ob->data == nullptr || !ID_IS_EDITABLE(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob->data)) {
1004 return false;
1005 }
1006
1007 return true;
1008}
1009
1011{
1012 using namespace blender::ed;
1013 wmMsgBus *mbus = CTX_wm_message_bus(C);
1014 Main &bmain = *CTX_data_main(C);
1015 Scene &scene = *CTX_data_scene(C);
1017 const int mode_flag = OB_MODE_TEXTURE_PAINT;
1018 const bool is_mode_set = (ob.mode & mode_flag) != 0;
1019
1020 if (!is_mode_set) {
1021 if (!object::mode_compat_set(C, &ob, eObjectMode(mode_flag), op->reports)) {
1022 return OPERATOR_CANCELLED;
1023 }
1024 }
1025
1026 if (ob.mode & mode_flag) {
1027 ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
1028 }
1029 else {
1032 }
1033
1034 WM_msg_publish_rna_prop(mbus, &ob.id, &ob, Object, mode);
1035
1037
1038 return OPERATOR_FINISHED;
1039}
1040
1042{
1043 /* identifiers */
1044 ot->name = "Texture Paint Mode";
1045 ot->idname = "PAINT_OT_texture_paint_toggle";
1046 ot->description = "Toggle texture paint mode in 3D view";
1047
1048 /* API callbacks. */
1051
1052 /* flags */
1053 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1054}
1055
1057
1058/* -------------------------------------------------------------------- */
1061
1063{
1064 Scene &scene = *CTX_data_scene(C);
1065
1067 Brush *br = BKE_paint_brush(paint);
1068
1069 if (BKE_paint_use_unified_color(scene.toolsettings, paint)) {
1071 swap_v3_v3(ups.rgb, ups.secondary_rgb);
1072 }
1073 else if (br) {
1074 swap_v3_v3(br->rgb, br->secondary_rgb);
1076 }
1077 else {
1078 return OPERATOR_CANCELLED;
1079 }
1080
1082
1083 return OPERATOR_FINISHED;
1084}
1085
1087{
1089 Brush *br = image_paint_brush(C);
1091 return true;
1092 }
1093 }
1094 else {
1096 if (ob != nullptr) {
1098 return true;
1099 }
1102 {
1103 return true;
1104 }
1105 }
1106 }
1107 return false;
1108}
1109
1111{
1112 /* identifiers */
1113 ot->name = "Swap Colors";
1114 ot->idname = "PAINT_OT_brush_colors_flip";
1115 ot->description = "Swap primary and secondary brush colors";
1116
1117 /* API callbacks. */
1118 ot->exec = brush_colors_flip_exec;
1119 ot->poll = brush_colors_flip_poll;
1120
1121 /* flags */
1122 ot->flag = OPTYPE_REGISTER;
1123}
1124
1126
1127/* -------------------------------------------------------------------- */
1130
1131void ED_imapaint_bucket_fill(bContext *C, float const color[3], wmOperator *op, const int mouse[2])
1132{
1134
1135 if (sima && sima->image) {
1136 Image *ima = sima->image;
1137
1139
1140 const float mouse_init[2] = {float(mouse[0]), float(mouse[1])};
1141 paint_2d_bucket_fill(C, color, nullptr, mouse_init, nullptr, nullptr);
1142
1144
1145 DEG_id_tag_update(&ima->id, 0);
1146 }
1147}
1148
1150{
1153 return true;
1154 }
1155 }
1156
1157 return false;
1158}
1159
1165
1170
1175
1180
1185
const float * BKE_brush_secondary_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1172
void BKE_brush_color_set(Scene *scene, const Paint *paint, Brush *brush, const float color[3])
Definition brush.cc:1182
const std::optional< BrushColorJitterSettings > BKE_brush_color_jitter_get_settings(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1137
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1128
void BKE_brush_tag_unsaved_changes(Brush *brush)
Definition brush.cc:720
bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4])
Definition colorband.cc:395
SpaceImage * CTX_wm_space_image(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmMsgBus * CTX_wm_message_bus(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
Definition image_gpu.cc:896
void BKE_image_mark_dirty(Image *image, ImBuf *ibuf)
void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
Definition image_gpu.cc:920
void BKE_image_free_all_gputextures(Main *bmain)
Definition image_gpu.cc:575
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
General operations, lookup, etc. for materials.
void BKE_texpaint_slots_refresh_object(Scene *scene, Object *ob)
Material * BKE_object_material_get(Object *ob, short act)
Mesh * BKE_mesh_from_object(Object *ob)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
PaintMode
Definition BKE_paint.hh:93
blender::float3 BKE_paint_randomize_color(const BrushColorJitterSettings &color_jitter, const blender::float3 &initial_hsv_jitter, const float distance, const float pressure, const blender::float3 &color)
Definition paint.cc:1853
bool BKE_paint_use_unified_color(const ToolSettings *tool_settings, const Paint *paint)
Definition paint.cc:592
bool BKE_paint_select_elem_test(const Object *ob)
Definition paint.cc:1624
bool BKE_paint_select_vert_test(const Object *ob)
Definition paint.cc:1606
void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3], bool ensure_brushes=true)
Definition paint.cc:1769
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:467
const uchar PAINT_CURSOR_TEXTURE_PAINT[3]
Definition paint.cc:243
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:636
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:496
bool BKE_paint_select_face_test(const Object *ob)
Definition paint.cc:1599
void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
Definition paint.cc:1109
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2623
blender::ocio::Display ColorManagedDisplay
Definition BLF_api.hh:35
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void mul_m4_v3(const float M[4][4], float r[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void swap_v3_v3(float a[3], float b[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
void BLI_rcti_init_minmax(struct rcti *rect)
Definition rct.cc:474
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
bool BLI_rcti_is_empty(const struct rcti *rect)
void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#define ELEM(...)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
eBlurKernelType
@ KERNEL_BOX
@ KERNEL_GAUSSIAN
@ BRUSH_DRAG_DOT
@ BRUSH_ANCHORED
@ BRUSH_USE_GRADIENT
@ BRUSH_AIRBRUSH
@ IMAGE_PAINT_BRUSH_TYPE_FILL
@ 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_PRESSURE
@ BRUSH_GRADIENT_SPACING_REPEAT
eObjectMode
@ OB_MODE_SCULPT
@ OB_MODE_TEXTURE_PAINT
@ OB_MODE_VERTEX_PAINT
Object is a sort of wrapper for general info.
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_CURVES
#define IMAGEPAINT_MODE_IMAGE
#define IMAGEPAINT_MODE_MATERIAL
@ PAINT_SHOW_BRUSH
@ RGN_TYPE_WINDOW
@ SPACE_IMAGE
@ SI_MODE_PAINT
@ MTEX_MAP_MODE_3D
@ MTEX_MAP_MODE_STENCIL
@ MTEX_MAP_MODE_TILED
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void ED_space_image_sync(Main *bmain, Image *image, bool ignore_render_viewer)
Definition image_edit.cc:70
bool ED_image_tools_paint_poll(bContext *C)
void ED_space_image_get_zoom(SpaceImage *sima, const ARegion *region, float *r_zoomx, float *r_zoomy)
void ED_paint_cursor_start(Paint *paint, bool(*poll)(bContext *C))
void * ED_image_paint_tile_push(PaintTileMap *paint_tile_map, Image *image, ImBuf *ibuf, ImBuf **tmpibuf, ImageUser *iuser, int x_tile, int y_tile, unsigned short **r_mask, bool **r_valid, bool use_thread_lock, bool find_prev)
void ED_image_undo_push_begin(const char *name, PaintMode paint_mode)
void ED_image_undo_push_end()
PaintTileMap * ED_image_paint_tile_map_get()
bool ED_paint_proj_mesh_data_check(Scene &scene, Object &ob, bool *r_has_uvs, bool *r_has_mat, bool *r_has_tex, bool *r_has_stencil)
#define ED_IMAGE_UNDO_TILE_BITS
Definition ED_paint.hh:113
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1040
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], const ColorManagedDisplay *display)
void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
void IMB_rectclip(ImBuf *dbuf, const ImBuf *sbuf, int *destx, int *desty, int *srcx, int *srcy, int *width, int *height)
Definition rectop.cc:308
void IMB_freeImBuf(ImBuf *ibuf)
@ IB_MIPMAP_INVALID
Read Guarded memory(de)allocation.
void ntreeTexEndExecTree(struct bNodeTreeExec *exec)
struct bNodeTreeExec * ntreeTexBeginExecTree(struct bNodeTree *ntree)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
#define UI_MAX_DRAW_STR
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:1667
#define NC_BRUSH
Definition WM_types.hh:382
@ KM_PRESS
Definition WM_types.hh:308
@ KM_RELEASE
Definition WM_types.hh:309
#define ND_MODE
Definition WM_types.hh:442
#define NC_SCENE
Definition WM_types.hh:375
#define NA_EDITED
Definition WM_types.hh:581
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define U
BMesh const char void * data
BPy_StructRNA * depsgraph
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static RandomNumberGenerator from_random_seed()
Definition rand.cc:288
#define exp
VecBase< float, 3 > float3
#define printf(...)
float distance(VecOp< float, D >, VecOp< float, D >) RET
#define ID_IS_EDITABLE(_id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
bool enabled
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 fmod(const float2 a, const float b)
bool grease_pencil_vertex_painting_poll(bContext *C)
bool grease_pencil_painting_poll(bContext *C)
bool mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports)
T midpoint(const T &a, const T &b)
VecBase< float, 3 > float3
void paint_cursor_delete_textures()
void paint_delete_blur_kernel(BlurKernel *kernel)
static wmOperatorStatus brush_colors_flip_exec(bContext *C, wmOperator *)
static wmOperatorStatus grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void ED_object_texture_paint_mode_enter_ex(Main &bmain, Scene &scene, Depsgraph &depsgraph, Object &ob)
static bool image_paint_2d_clone_poll(bContext *C)
bool ED_image_tools_paint_poll(bContext *C)
static Brush * image_paint_brush(bContext *C)
static bool image_paint_poll_ex(bContext *C, bool check_tool)
void paint_init_pivot(Object *ob, Scene *scene)
static bool texture_paint_poll(bContext *C)
bool vert_paint_poll(bContext *C)
static void grab_clone_cancel(bContext *, wmOperator *op)
static blender::float3 paint_init_pivot_mesh(Object *ob)
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
void ED_imapaint_bucket_fill(bContext *C, float const color[3], wmOperator *op, const int mouse[2])
void paint_brush_init_tex(Brush *brush)
static bool texture_paint_toggle_poll(bContext *C)
void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, ImageUser *iuser, int x, int y, int w, int h, bool find_old)
static wmOperatorStatus grab_clone_exec(bContext *C, wmOperator *op)
static blender::float3 paint_init_pivot_grease_pencil(Object *ob, const int frame)
void ED_object_texture_paint_mode_exit(bContext *C)
static wmOperatorStatus sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool paint_use_opacity_masking(const Scene *scene, const Paint *paint, const Brush *brush)
bool facemask_paint_poll(bContext *C)
bool image_texture_paint_poll(bContext *C)
void PAINT_OT_sample_color(wmOperatorType *ot)
blender::float3 seed_hsv_jitter()
static void sample_color_update_header(SampleColorData *data, bContext *C)
static ImagePaintPartialRedraw imapaintpartial
void PAINT_OT_texture_paint_toggle(wmOperatorType *ot)
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
bool mask_paint_poll(bContext *C)
static wmOperatorStatus sample_color_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event)
BlurKernel * paint_new_blur_kernel(Brush *br, bool proj)
static blender::float3 paint_init_pivot_curves(Object *ob)
void ED_object_texture_paint_mode_enter(bContext *C)
static void grab_clone_apply(bContext *C, wmOperator *op)
void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
void paint_brush_color_get(Scene *scene, const Paint *paint, Brush *br, std::optional< blender::float3 > &initial_hsv_jitter, bool color_correction, bool invert, float distance, float pressure, const ColorManagedDisplay *display, float r_color[3])
bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
static bool brush_colors_flip_poll(bContext *C)
void PAINT_OT_grab_clone(wmOperatorType *ot)
void paint_brush_exit_tex(Brush *brush)
static wmOperatorStatus texture_paint_toggle_exec(bContext *C, wmOperator *op)
void ED_object_texture_paint_mode_exit_ex(Main &bmain, Scene &scene, Object &ob)
static bool sample_color_poll(bContext *C)
void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
static void toggle_paint_cursor(Scene &scene, bool enable)
static bool image_paint_poll_ignore_tool(bContext *C)
static wmOperatorStatus sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
void set_imapaintpartial(ImagePaintPartialRedraw *ippr)
void ED_imapaint_clear_partial_redraw()
ImagePaintPartialRedraw * get_imapaintpartial()
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)
bool vertex_paint_poll_ignore_tool(bContext *C)
void paint_sample_color(bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool palette)
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_int_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const int *default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
#define FLT_MAX
Definition stdcycles.h:14
float * wdata
struct ColorBand * gradient
int blur_kernel_radius
struct MTex mtex
char image_brush_type
float rgb[3]
char gradient_stroke_mode
struct MTex mask_mtex
int gradient_spacing
float secondary_rgb[3]
CurvesGeometry geometry
float startoffset[2]
unsigned char planes
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
struct Image * canvas
void * first
char brush_map_mode
struct Tex * tex
short paint_active_slot
struct TexPaintSlot * texpaintslot
void * paint_cursor
struct ToolSettings * toolsettings
struct RenderData r
ListBase spacedata
struct Image * image
struct Image * ima
struct bNodeTree * nodetree
struct ImagePaintSettings imapaint
struct UnifiedPaintSettings unified_paint_settings
bNodeTreeRuntimeHandle * runtime
ListBase areabase
int ymin
int xmin
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
int xy[2]
Definition WM_types.hh:758
int mval[2]
Definition WM_types.hh:760
const char * name
Definition WM_types.hh:1030
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_EYEDROPPER
Definition wm_cursors.hh:36
void WM_redraw_windows(bContext *C)
Definition wm_draw.cc:1661
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *)
Definition wm_draw.cc:1573
int WM_userdef_event_type_from_keymap_type(int kmitype)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
wmOperatorType * ot
Definition wm_files.cc:4226
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
bool WM_paint_cursor_end(wmPaintCursor *handle)
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
void WM_toolsystem_update_from_context_view3d(bContext *C)
bScreen * WM_window_get_active_screen(const wmWindow *win)