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
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/* -------------------------------------------------------------------- */
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);
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{
153 return;
154 }
155
156 if (ibuf->mipmap[0]) {
158 }
159
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)) {
180 /* Testing with partial update in uv editor too. */
183 }
184}
185
188/* -------------------------------------------------------------------- */
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
270/* -------------------------------------------------------------------- */
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
344/* -------------------------------------------------------------------- */
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 }
391 BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr);
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
457/* -------------------------------------------------------------------- */
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
506/* -------------------------------------------------------------------- */
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 */
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
621/* -------------------------------------------------------------------- */
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 */
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
804/* -------------------------------------------------------------------- */
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{
848 UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
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
933{
934 Main &bmain = *CTX_data_main(C);
936 Scene &scene = *CTX_data_scene(C);
937 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
938
940}
941
943{
944 ob.mode &= ~OB_MODE_TEXTURE_PAINT;
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
959{
960 Main &bmain = *CTX_data_main(C);
962 Scene &scene = *CTX_data_scene(C);
963 ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
964}
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;
982 wmMsgBus *mbus = CTX_wm_message_bus(C);
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 */
1023}
1024
1027/* -------------------------------------------------------------------- */
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)) {
1039 UnifiedPaintSettings &ups = scene.toolsettings->unified_paint_settings;
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 */
1089
1090 /* flags */
1092}
1093
1096/* -------------------------------------------------------------------- */
1100void ED_imapaint_bucket_fill(bContext *C, float const color[3], wmOperator *op, const int mouse[2])
1101{
1102 SpaceImage *sima = CTX_wm_space_image(C);
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
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.
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 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
@ 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 NC_BRUSH
Definition WM_types.hh:352
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define ND_MODE
Definition WM_types.hh:412
#define NC_SCENE
Definition WM_types.hh:345
#define NA_EDITED
Definition WM_types.hh:550
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
#define printf
const Depsgraph * depsgraph
draw_view in_light_buf[] float
void IMB_freeImBuf(ImBuf *)
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)
T midpoint(const T &a, const T &b)
VecBase< float, 3 > float3
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]
float startoffset[2]
unsigned char planes
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
struct Image * canvas
char brush_map_mode
struct Tex * tex
short paint_active_slot
struct TexPaintSlot * texpaintslot
void * paint_cursor
struct Image * image
struct Image * ima
struct bNodeTree * nodetree
bNodeTreeRuntimeHandle * runtime
int ymin
int ymax
int xmin
int xmax
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
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
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)