Blender V4.3
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_math_vector.hh"
18#include "BLI_string.h"
19#include "BLI_utildefines.h"
20
21#include "BLT_translation.hh"
22
23#include "IMB_imbuf.hh"
24#include "IMB_imbuf_types.hh"
25
26#include "DNA_brush_types.h"
27#include "DNA_material_types.h"
28#include "DNA_mesh_types.h"
29#include "DNA_node_types.h"
30#include "DNA_object_types.h"
31#include "DNA_scene_types.h"
32
33#include "BKE_brush.hh"
34#include "BKE_colorband.hh"
35#include "BKE_context.hh"
36#include "BKE_curves.hh"
37#include "BKE_grease_pencil.hh"
38#include "BKE_image.hh"
39#include "BKE_main.hh"
40#include "BKE_material.h"
41#include "BKE_mesh.hh"
42#include "BKE_node_runtime.hh"
43#include "BKE_object.hh"
44#include "BKE_paint.hh"
45#include "BKE_scene.hh"
46
47#include "NOD_texture.h"
48
49#include "DEG_depsgraph.hh"
51
52#include "UI_interface.hh"
53#include "UI_view2d.hh"
54
55#include "ED_grease_pencil.hh"
56#include "ED_image.hh"
57#include "ED_object.hh"
58#include "ED_paint.hh"
59#include "ED_screen.hh"
60
61#include "WM_api.hh"
62#include "WM_message.hh"
63#include "WM_toolsystem.hh"
64#include "WM_types.hh"
65
66#include "RNA_access.hh"
67#include "RNA_define.hh"
68
70
71#include "paint_intern.hh"
72
73/* -------------------------------------------------------------------- */
76
83
88
93
94/* Image paint Partial Redraw & Dirty Region. */
95
100
102 ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
103{
104 int srcx = 0, srcy = 0;
105
106 IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
107
108 *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
109 *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
110 *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
111 *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
112}
113
115 Image *ima, ImBuf *ibuf, ImageUser *iuser, int x, int y, int w, int h, bool find_old)
116{
117 ImBuf *tmpibuf = nullptr;
118 int tilex, tiley, tilew, tileh, tx, ty;
119 int srcx = 0, srcy = 0;
120
121 IMB_rectclip(ibuf, nullptr, &x, &y, &srcx, &srcy, &w, &h);
122
123 if (w == 0 || h == 0) {
124 return;
125 }
126
127 rcti rect_to_merge;
128 BLI_rcti_init(&rect_to_merge, x, x + w, y, y + h);
129 BLI_rcti_do_minmax_rcti(&imapaintpartial.dirty_region, &rect_to_merge);
130
131 imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
132
134
135 for (ty = tiley; ty <= tileh; ty++) {
136 for (tx = tilex; tx <= tilew; tx++) {
138 undo_tiles, ima, ibuf, &tmpibuf, iuser, tx, ty, nullptr, nullptr, false, find_old);
139 }
140 }
141
142 BKE_image_mark_dirty(ima, ibuf);
143
144 if (tmpibuf) {
145 IMB_freeImBuf(tmpibuf);
146 }
147}
148
150 SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
151{
152 if (BLI_rcti_is_empty(&imapaintpartial.dirty_region)) {
153 return;
154 }
155
156 if (ibuf->mipmap[0]) {
158 }
159
161 imapaintpartial.dirty_region.xmin,
162 imapaintpartial.dirty_region.ymin,
163 imapaintpartial.dirty_region.xmax,
164 imapaintpartial.dirty_region.ymax);
165
166 /* When buffer is partial updated the planes should be set to a larger value than 8. This will
167 * make sure that partial updating is working but uses more GPU memory as the gpu texture will
168 * have 4 channels. When so the whole texture needs to be re-uploaded to the GPU using the new
169 * texture format. */
170 if (ibuf != nullptr && ibuf->planes == 8) {
171 ibuf->planes = 32;
173 return;
174 }
175
176 /* TODO: should set_tpage create ->rect? */
177 if (texpaint || (sima && sima->lock)) {
178 const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region);
179 const int h = BLI_rcti_size_y(&imapaintpartial.dirty_region);
180 /* Testing with partial update in uv editor too. */
182 image, iuser, imapaintpartial.dirty_region.xmin, imapaintpartial.dirty_region.ymin, w, h);
183 }
184}
185
187
188/* -------------------------------------------------------------------- */
191
193{
194 int i, j;
195 BlurKernel *kernel = MEM_new<BlurKernel>("BlurKernel");
196
197 float radius;
198 int side;
199 eBlurKernelType type = static_cast<eBlurKernelType>(br->blur_mode);
200
201 if (proj) {
202 radius = 0.5f;
203
204 side = kernel->side = 2;
205 kernel->side_squared = kernel->side * kernel->side;
206 kernel->wdata = static_cast<float *>(
207 MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data"));
208 kernel->pixel_len = radius;
209 }
210 else {
211 if (br->blur_kernel_radius <= 0) {
212 br->blur_kernel_radius = 1;
213 }
214
215 radius = br->blur_kernel_radius;
216
217 side = kernel->side = radius * 2 + 1;
218 kernel->side_squared = kernel->side * kernel->side;
219 kernel->wdata = static_cast<float *>(
220 MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data"));
221 kernel->pixel_len = br->blur_kernel_radius;
222 }
223
224 switch (type) {
225 case KERNEL_BOX:
226 for (i = 0; i < kernel->side_squared; i++) {
227 kernel->wdata[i] = 1.0;
228 }
229 break;
230
231 case KERNEL_GAUSSIAN: {
232 /* at 3.0 standard deviations distance, kernel is about zero */
233 float standard_dev = radius / 3.0f;
234
235 /* make the necessary adjustment to the value for use in the normal distribution formula */
236 standard_dev = -standard_dev * standard_dev * 2;
237
238 for (i = 0; i < side; i++) {
239 for (j = 0; j < side; j++) {
240 float idist = radius - i;
241 float jdist = radius - j;
242 float value = exp((idist * idist + jdist * jdist) / standard_dev);
243
244 kernel->wdata[i + j * side] = value;
245 }
246 }
247
248 break;
249 }
250
251 default:
252 printf("unidentified kernel type, aborting\n");
254 MEM_delete(kernel);
255 return nullptr;
256 }
257
258 return kernel;
259}
260
262{
263 if (kernel->wdata) {
264 MEM_freeN(kernel->wdata);
265 }
266}
267
269
270/* -------------------------------------------------------------------- */
273
275{
276 Scene *scene = CTX_data_scene(C);
277 ToolSettings *settings = scene->toolsettings;
278
279 return BKE_paint_brush(&settings->imapaint.paint);
280}
281
282static bool image_paint_poll_ex(bContext *C, bool check_tool)
283{
284 Object *obact;
285
286 if (!image_paint_brush(C)) {
287 return false;
288 }
289
290 obact = CTX_data_active_object(C);
291 if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
292 if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
293 return true;
294 }
295 }
296 else {
298
299 if (sima) {
300 if (sima->image != nullptr &&
302 {
303 return false;
304 }
305 if (sima->mode == SI_MODE_PAINT) {
306 const ARegion *region = CTX_wm_region(C);
307 if (region->regiontype == RGN_TYPE_WINDOW) {
308 return true;
309 }
310 }
311 }
312 }
313
314 return false;
315}
316
318{
319 return image_paint_poll_ex(C, true);
320}
321
323{
324 return image_paint_poll_ex(C, false);
325}
326
328{
329 Brush *brush = image_paint_brush(C);
330
332 if (brush && (brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_CLONE)) {
333 if (brush->clone.image) {
334 return true;
335 }
336 }
337 }
338
339 return false;
340}
341
343
344/* -------------------------------------------------------------------- */
347
349{
350 return ((brush->flag & BRUSH_AIRBRUSH) || (brush->flag & BRUSH_DRAG_DOT) ||
351 (brush->flag & BRUSH_ANCHORED) ||
352 ELEM(brush->image_brush_type,
356 (brush->flag & BRUSH_USE_GRADIENT) ||
357 (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode,
361 false :
362 true);
363}
364
366 const Paint *paint,
367 Brush *br,
368 bool color_correction,
369 bool invert,
370 float distance,
371 float pressure,
372 ColorManagedDisplay *display,
373 float r_color[3])
374{
375 if (invert) {
376 copy_v3_v3(r_color, BKE_brush_secondary_color_get(scene, paint, br));
377 }
378 else {
379 if (br->flag & BRUSH_USE_GRADIENT) {
380 float color_gr[4];
381 switch (br->gradient_stroke_mode) {
383 BKE_colorband_evaluate(br->gradient, pressure, color_gr);
384 break;
386 float coord = fmod(distance / br->gradient_spacing, 1.0);
387 BKE_colorband_evaluate(br->gradient, coord, color_gr);
388 break;
389 }
392 break;
393 }
394 }
395 /* Gradient / Color-band colors are not considered #PROP_COLOR_GAMMA.
396 * Brush colors are expected to be in sRGB though. */
398 }
399 else {
400 copy_v3_v3(r_color, BKE_brush_color_get(scene, paint, br));
401 }
402 }
403 if (color_correction) {
405 }
406}
407
409{
410 /* init mtex nodes */
411 if (brush) {
412 MTex *mtex = &brush->mtex;
413 if (mtex->tex && mtex->tex->nodetree) {
414 /* has internal flag to detect it only does it once */
416 }
417 mtex = &brush->mask_mtex;
418 if (mtex->tex && mtex->tex->nodetree) {
420 }
421 }
422}
423
425{
426 if (brush) {
427 MTex *mtex = &brush->mtex;
428 if (mtex->tex && mtex->tex->nodetree) {
429 ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
430 }
431 mtex = &brush->mask_mtex;
432 if (mtex->tex && mtex->tex->nodetree) {
433 ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
434 }
435 }
436}
437
438bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
439{
440 ScrArea *area = CTX_wm_area(C);
441 if (area && area->spacetype == SPACE_IMAGE) {
442 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
443 if (sima->mode == SI_MODE_PAINT) {
444 ARegion *region = CTX_wm_region(C);
445 ED_space_image_get_zoom(sima, region, zoomx, zoomy);
446 return true;
447 }
448 }
449
450 *zoomx = *zoomy = 1;
451
452 return false;
453}
454
456
457/* -------------------------------------------------------------------- */
460
461static void toggle_paint_cursor(Scene &scene, bool enable)
462{
463 ToolSettings *settings = scene.toolsettings;
464 Paint &p = settings->imapaint.paint;
465
466 if (p.paint_cursor && !enable) {
468 p.paint_cursor = nullptr;
470 }
471 else if (enable) {
473 }
474}
475
477{
478 ToolSettings *settings = scene->toolsettings;
479 ImagePaintSettings *imapaint = &settings->imapaint;
480 bool enabled = false;
481
482 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
484
485 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
486 if (area->spacetype == SPACE_IMAGE) {
487 if (((SpaceImage *)area->spacedata.first)->mode == SI_MODE_PAINT) {
488 enabled = true;
489 }
490 }
491 }
492 }
493
494 if (enabled) {
496
498 }
499 else {
501 }
502}
503
505
506/* -------------------------------------------------------------------- */
509
510struct GrabClone {
511 float startoffset[2];
513};
514
516{
517 Brush *brush = image_paint_brush(C);
518 float delta[2];
519
520 RNA_float_get_array(op->ptr, "delta", delta);
521 add_v2_v2(brush->clone.offset, delta);
524}
525
527{
528 grab_clone_apply(C, op);
529
530 return OPERATOR_FINISHED;
531}
532
533static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
534{
535 Brush *brush = image_paint_brush(C);
536 GrabClone *cmv;
537
538 cmv = MEM_cnew<GrabClone>("GrabClone");
539 copy_v2_v2(cmv->startoffset, brush->clone.offset);
540 cmv->startx = event->xy[0];
541 cmv->starty = event->xy[1];
542 op->customdata = cmv;
543
545
547}
548
549static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event)
550{
551 Brush *brush = image_paint_brush(C);
552 ARegion *region = CTX_wm_region(C);
553 GrabClone *cmv = static_cast<GrabClone *>(op->customdata);
554 float startfx, startfy, fx, fy, delta[2];
555 int xmin = region->winrct.xmin, ymin = region->winrct.ymin;
556
557 switch (event->type) {
558 case LEFTMOUSE:
559 case MIDDLEMOUSE:
560 case RIGHTMOUSE: /* XXX hardcoded */
562 return OPERATOR_FINISHED;
563 case MOUSEMOVE:
564 /* mouse moved, so move the clone image */
566 &region->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy);
567 UI_view2d_region_to_view(&region->v2d, event->xy[0] - xmin, event->xy[1] - ymin, &fx, &fy);
568
569 delta[0] = fx - startfx;
570 delta[1] = fy - startfy;
571 RNA_float_set_array(op->ptr, "delta", delta);
572
573 copy_v2_v2(brush->clone.offset, cmv->startoffset);
575
576 grab_clone_apply(C, op);
577 break;
578 }
579
581}
582
583static void grab_clone_cancel(bContext * /*C*/, wmOperator *op)
584{
585 GrabClone *cmv = static_cast<GrabClone *>(op->customdata);
586 MEM_delete(cmv);
587}
588
590{
591 /* identifiers */
592 ot->name = "Grab Clone";
593 ot->idname = "PAINT_OT_grab_clone";
594 ot->description = "Move the clone source image";
595
596 /* api callbacks */
597 ot->exec = grab_clone_exec;
598 ot->invoke = grab_clone_invoke;
599 ot->modal = grab_clone_modal;
600 ot->cancel = grab_clone_cancel;
602
603 /* flags */
605
606 /* properties */
608 "delta",
609 2,
610 nullptr,
611 -FLT_MAX,
612 FLT_MAX,
613 "Delta",
614 "Delta offset of clone image in 0.0 to 1.0 coordinates",
615 -1.0f,
616 1.0f);
617}
618
620
621/* -------------------------------------------------------------------- */
624
631
633{
634 char msg[UI_MAX_DRAW_STR];
635 ScrArea *area = CTX_wm_area(C);
636
637 if (area) {
638 SNPRINTF(msg,
639 IFACE_("Sample color for %s"),
640 !data->sample_palette ?
641 IFACE_("Brush. Use Left Click to sample for palette instead") :
642 IFACE_("Palette. Use Left Click to sample more colors"));
644 }
645}
646
648{
650 Brush *brush = BKE_paint_brush(paint);
652 ARegion *region = CTX_wm_region(C);
653 wmWindow *win = CTX_wm_window(C);
654 const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
655 int location[2];
656 paint->flags &= ~PAINT_SHOW_BRUSH;
657
658 /* force redraw without cursor */
659 WM_paint_cursor_tag_redraw(win, region);
661
662 RNA_int_get_array(op->ptr, "location", location);
663 const bool use_palette = RNA_boolean_get(op->ptr, "palette");
664 const bool use_sample_texture = (mode == PaintMode::Texture3D) &&
665 !RNA_boolean_get(op->ptr, "merged");
666
667 paint_sample_color(C, region, location[0], location[1], use_sample_texture, use_palette);
668
669 if (show_cursor) {
670 paint->flags |= PAINT_SHOW_BRUSH;
671 }
672
674
675 return OPERATOR_FINISHED;
676}
677
678static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
679{
680 Scene *scene = CTX_data_scene(C);
682 Brush *brush = BKE_paint_brush(paint);
683 SampleColorData *data = MEM_new<SampleColorData>("sample color custom data");
684 ARegion *region = CTX_wm_region(C);
685 wmWindow *win = CTX_wm_window(C);
686
687 data->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
688 data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
689 copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, paint, brush));
690 data->sample_palette = false;
691 op->customdata = data;
692 paint->flags &= ~PAINT_SHOW_BRUSH;
693
695
697
698 /* force redraw without cursor */
699 WM_paint_cursor_tag_redraw(win, region);
701
702 RNA_int_set_array(op->ptr, "location", event->mval);
703
705 const bool use_sample_texture = (mode == PaintMode::Texture3D) &&
706 !RNA_boolean_get(op->ptr, "merged");
707
708 paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, false);
710
712
714}
715
716static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
717{
718 Scene *scene = CTX_data_scene(C);
719 SampleColorData *data = static_cast<SampleColorData *>(op->customdata);
721 Brush *brush = BKE_paint_brush(paint);
722
723 if ((event->type == data->launch_event) && (event->val == KM_RELEASE)) {
724 if (data->show_cursor) {
725 paint->flags |= PAINT_SHOW_BRUSH;
726 }
727
728 if (data->sample_palette) {
729 BKE_brush_color_set(scene, paint, brush, data->initcolor);
730 RNA_boolean_set(op->ptr, "palette", true);
731 }
733 MEM_delete(data);
734 ED_workspace_status_text(C, nullptr);
735
736 return OPERATOR_FINISHED;
737 }
738
740 const bool use_sample_texture = (mode == PaintMode::Texture3D) &&
741 !RNA_boolean_get(op->ptr, "merged");
742
743 switch (event->type) {
744 case MOUSEMOVE: {
745 ARegion *region = CTX_wm_region(C);
746 RNA_int_set_array(op->ptr, "location", event->mval);
747 paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, false);
749 break;
750 }
751
752 case LEFTMOUSE:
753 if (event->val == KM_PRESS) {
754 ARegion *region = CTX_wm_region(C);
755 RNA_int_set_array(op->ptr, "location", event->mval);
756 paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, true);
757 if (!data->sample_palette) {
758 data->sample_palette = true;
760 }
762 }
763 break;
764 }
765
767}
768
774
776{
777 /* identifiers */
778 ot->name = "Sample Color";
779 ot->idname = "PAINT_OT_sample_color";
780 ot->description = "Use the mouse to sample a color in the image";
781
782 /* api callbacks */
783 ot->exec = sample_color_exec;
784 ot->invoke = sample_color_invoke;
785 ot->modal = sample_color_modal;
786 ot->poll = sample_color_poll;
787
788 /* flags */
790
791 /* properties */
792 PropertyRNA *prop;
793
794 prop = RNA_def_int_vector(
795 ot->srna, "location", 2, nullptr, 0, INT_MAX, "Location", "", 0, 16384);
797
798 RNA_def_boolean(ot->srna, "merged", false, "Sample Merged", "Sample the output display color");
799 RNA_def_boolean(ot->srna, "palette", false, "Add to Palette", "");
800}
801
803
804/* -------------------------------------------------------------------- */
807
809{
810 using namespace blender;
811 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
812 if (!mesh_eval) {
813 mesh_eval = (const Mesh *)ob->data;
814 }
815
816 const std::optional<Bounds<float3>> bounds = mesh_eval->bounds_min_max();
817 if (!bounds) {
818 return float3(0.0f);
819 }
820
821 return math::midpoint(bounds->min, bounds->max);
822}
823
825{
826 const Curves &curves = *static_cast<const Curves *>(ob->data);
827 const std::optional<blender::Bounds<blender::float3>> bounds =
828 curves.geometry.wrap().bounds_min_max();
829 if (bounds.has_value()) {
830 return blender::math::midpoint(bounds->min, bounds->max);
831 }
832 return blender::float3(0);
833}
834
836{
837 using namespace blender;
838 const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(ob->data);
839 const std::optional<Bounds<float3>> bounds = grease_pencil.bounds_min_max(frame);
840 if (bounds.has_value()) {
841 return blender::math::midpoint(bounds->min, bounds->max);
842 }
843 return float3(0.0f);
844}
845
847{
849
850 blender::float3 location;
851 switch (ob->type) {
852 case OB_MESH:
853 location = paint_init_pivot_mesh(ob);
854 break;
855 case OB_CURVES:
856 location = paint_init_pivot_curves(ob);
857 break;
858 case OB_GREASE_PENCIL:
859 location = paint_init_pivot_grease_pencil(ob, scene->r.cfra);
860 break;
861 default:
863 ups->last_stroke_valid = false;
864 return;
865 }
866
867 mul_m4_v3(ob->object_to_world().ptr(), location);
868
869 ups->last_stroke_valid = true;
870 ups->average_stroke_counter = 1;
871 copy_v3_v3(ups->average_stroke_accum, location);
872}
873
875 Scene &scene,
876 Depsgraph &depsgraph,
877 Object &ob)
878{
879 Image *ima = nullptr;
880 ImagePaintSettings &imapaint = scene.toolsettings->imapaint;
881
882 /* This has to stay here to regenerate the texture paint
883 * cache in case we are loading a file */
885
886 ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
887
888 /* entering paint mode also sets image to editors */
889 if (imapaint.mode == IMAGEPAINT_MODE_MATERIAL) {
890 /* set the current material active paint slot on image editor */
892
893 if (ma && ma->texpaintslot) {
894 ima = ma->texpaintslot[ma->paint_active_slot].ima;
895 }
896 }
897 else if (imapaint.mode == IMAGEPAINT_MODE_IMAGE) {
898 ima = imapaint.canvas;
899 }
900
901 if (ima) {
902 ED_space_image_sync(&bmain, ima, false);
903 }
904
906
908
909 BKE_paint_brushes_validate(&bmain, &imapaint.paint);
910
911 if (U.glreslimit != 0) {
913 }
914 BKE_image_paint_set_mipmap(&bmain, false);
915
916 toggle_paint_cursor(scene, true);
917
918 Mesh *mesh = BKE_mesh_from_object(&ob);
919 BLI_assert(mesh != nullptr);
921
922 /* Ensure we have evaluated data for bounding box. */
924
925 /* Set pivot to bounding box center. */
926 Object *ob_eval = DEG_get_evaluated_object(&depsgraph, &ob);
927 paint_init_pivot(ob_eval ? ob_eval : &ob, &scene);
928
930}
931
941
943{
945
946 if (U.glreslimit != 0) {
948 }
949 BKE_image_paint_set_mipmap(&bmain, true);
950 toggle_paint_cursor(scene, false);
951
952 Mesh *mesh = BKE_mesh_from_object(&ob);
953 BLI_assert(mesh != nullptr);
956}
957
965
967{
969 if (ob == nullptr || ob->type != OB_MESH) {
970 return false;
971 }
972 if (ob->data == nullptr || !ID_IS_EDITABLE(ob->data) || ID_IS_OVERRIDE_LIBRARY(ob->data)) {
973 return false;
974 }
975
976 return true;
977}
978
980{
981 using namespace blender::ed;
983 Main &bmain = *CTX_data_main(C);
984 Scene &scene = *CTX_data_scene(C);
986 const int mode_flag = OB_MODE_TEXTURE_PAINT;
987 const bool is_mode_set = (ob.mode & mode_flag) != 0;
988
989 if (!is_mode_set) {
990 if (!object::mode_compat_set(C, &ob, eObjectMode(mode_flag), op->reports)) {
991 return OPERATOR_CANCELLED;
992 }
993 }
994
995 if (ob.mode & mode_flag) {
996 ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
997 }
998 else {
1001 }
1002
1003 WM_msg_publish_rna_prop(mbus, &ob.id, &ob, Object, mode);
1004
1006
1007 return OPERATOR_FINISHED;
1008}
1009
1011{
1012 /* identifiers */
1013 ot->name = "Texture Paint Toggle";
1014 ot->idname = "PAINT_OT_texture_paint_toggle";
1015 ot->description = "Toggle texture paint mode in 3D view";
1016
1017 /* api callbacks */
1020
1021 /* flags */
1022 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1023}
1024
1026
1027/* -------------------------------------------------------------------- */
1030
1032{
1033 Scene &scene = *CTX_data_scene(C);
1034
1036 Brush *br = BKE_paint_brush(paint);
1037
1038 if (BKE_paint_use_unified_color(scene.toolsettings, paint)) {
1040 swap_v3_v3(ups.rgb, ups.secondary_rgb);
1041 }
1042 else if (br) {
1043 swap_v3_v3(br->rgb, br->secondary_rgb);
1045 }
1046 else {
1047 return OPERATOR_CANCELLED;
1048 }
1049
1051
1052 return OPERATOR_FINISHED;
1053}
1054
1056{
1058 Brush *br = image_paint_brush(C);
1060 return true;
1061 }
1062 }
1063 else {
1065 if (ob != nullptr) {
1067 return true;
1068 }
1071 {
1072 return true;
1073 }
1074 }
1075 }
1076 return false;
1077}
1078
1080{
1081 /* identifiers */
1082 ot->name = "Swap Colors";
1083 ot->idname = "PAINT_OT_brush_colors_flip";
1084 ot->description = "Swap primary and secondary brush colors";
1085
1086 /* api callbacks */
1087 ot->exec = brush_colors_flip_exec;
1088 ot->poll = brush_colors_flip_poll;
1089
1090 /* flags */
1091 ot->flag = OPTYPE_REGISTER;
1092}
1093
1095
1096/* -------------------------------------------------------------------- */
1099
1100void ED_imapaint_bucket_fill(bContext *C, float const color[3], wmOperator *op, const int mouse[2])
1101{
1103
1104 if (sima && sima->image) {
1105 Image *ima = sima->image;
1106
1108
1109 const float mouse_init[2] = {float(mouse[0]), float(mouse[1])};
1110 paint_2d_bucket_fill(C, color, nullptr, mouse_init, nullptr, nullptr);
1111
1113
1114 DEG_id_tag_update(&ima->id, 0);
1115 }
1116}
1117
1119{
1122 return true;
1123 }
1124 }
1125
1126 return false;
1127}
1128
1133
1138
1143
1148
const float * BKE_brush_secondary_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1037
void BKE_brush_color_set(Scene *scene, const Paint *paint, Brush *brush, const float color[3])
Definition brush.cc:1047
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1029
void BKE_brush_tag_unsaved_changes(Brush *brush)
Definition brush.cc:621
bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4])
Definition colorband.cc:396
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:882
void BKE_image_mark_dirty(Image *image, ImBuf *ibuf)
void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
Definition image_gpu.cc:906
void BKE_image_free_all_gputextures(Main *bmain)
Definition image_gpu.cc:561
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob)
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:99
bool BKE_paint_use_unified_color(const ToolSettings *tool_settings, const Paint *paint)
Definition paint.cc:605
bool BKE_paint_select_elem_test(const Object *ob)
Definition paint.cc:1632
bool BKE_paint_select_vert_test(const Object *ob)
Definition paint.cc:1614
void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3], bool ensure_brushes=true)
Definition paint.cc:1779
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:477
const uchar PAINT_CURSOR_TEXTURE_PAINT[3]
Definition paint.cc:246
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:506
bool BKE_paint_select_face_test(const Object *ob)
Definition paint.cc:1607
void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
Definition paint.cc:1108
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2573
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#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:193
void BLI_rcti_init_minmax(struct rcti *rect)
Definition rct.c:478
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
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:597
#define ELEM(...)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
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_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:106
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], 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:306
Contains defines and structs used throughout the imbuf module.
@ IB_MIPMAP_INVALID
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
void ntreeTexEndExecTree(struct bNodeTreeExec *exec)
struct bNodeTreeExec * ntreeTexBeginExecTree(struct bNodeTree *ntree)
PropertyFlag
Definition RNA_types.hh:201
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
#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:1663
#define NC_BRUSH
Definition WM_types.hh:352
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_MODE
Definition WM_types.hh:412
#define NC_SCENE
Definition WM_types.hh:345
#define NA_EDITED
Definition WM_types.hh:550
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define U
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
VecBase< float, 3 > float3
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
#define printf
draw_view in_light_buf[] float
void IMB_freeImBuf(ImBuf *)
bool enabled
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float3 exp(float3 v)
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
float distance(float a, float b)
void paint_cursor_delete_textures()
void paint_delete_blur_kernel(BlurKernel *kernel)
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 int texture_paint_toggle_exec(bContext *C, wmOperator *op)
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 int grab_clone_exec(bContext *C, 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 int sample_color_exec(bContext *C, wmOperator *op)
static blender::float3 paint_init_pivot_grease_pencil(Object *ob, const int frame)
static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event)
void ED_object_texture_paint_mode_exit(bContext *C)
bool facemask_paint_poll(bContext *C)
bool image_texture_paint_poll(bContext *C)
void PAINT_OT_sample_color(wmOperatorType *ot)
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)
BlurKernel * paint_new_blur_kernel(Brush *br, bool proj)
static blender::float3 paint_init_pivot_curves(Object *ob)
bool paint_use_opacity_masking(Brush *brush)
static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void ED_object_texture_paint_mode_enter(bContext *C)
static void grab_clone_apply(bContext *C, wmOperator *op)
static int brush_colors_flip_exec(bContext *C, wmOperator *)
void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
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_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)
static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
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 int sample_color_invoke(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 Image * image
float offset[2]
struct ColorBand * gradient
int blur_kernel_radius
struct BrushClone clone
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
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_EYEDROPPER
Definition wm_cursors.hh:35
void WM_redraw_windows(bContext *C)
Definition wm_draw.cc:1621
void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *)
Definition wm_draw.cc:1533
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:4125
#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)