Blender V4.3
image_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cerrno>
10#include <cstddef>
11#include <cstdlib>
12#include <cstring>
13#include <fcntl.h>
14#ifndef WIN32
15# include <unistd.h>
16#else
17# include <io.h>
18#endif
19
20#include "MEM_guardedalloc.h"
21
22#include "BLI_blenlib.h"
23#include "BLI_fileops.h"
24#include "BLI_ghash.h"
25#include "BLI_string.h"
26#include "BLI_time.h"
27#include "BLI_utildefines.h"
28
29#include "BLT_translation.hh"
30
31#include "DNA_camera_types.h"
32#include "DNA_node_types.h"
33#include "DNA_object_types.h"
34#include "DNA_scene_types.h"
35#include "DNA_screen_types.h"
36
37#include "BKE_colortools.hh"
38#include "BKE_context.hh"
39#include "BKE_global.hh"
40#include "BKE_icons.h"
41#include "BKE_image.hh"
42#include "BKE_image_save.hh"
43#include "BKE_layer.hh"
44#include "BKE_lib_id.hh"
45#include "BKE_main.hh"
46#include "BKE_packedFile.hh"
47#include "BKE_report.hh"
48#include "BKE_scene.hh"
49
50#include "DEG_depsgraph.hh"
51
53#include "IMB_imbuf.hh"
54#include "IMB_imbuf_types.hh"
55#include "IMB_moviecache.hh"
56
57#include "RE_pipeline.h"
58
59#include "RNA_access.hh"
60#include "RNA_define.hh"
61#include "RNA_enum_types.hh"
62#include "RNA_prototypes.hh"
63
64#include "ED_image.hh"
65#include "ED_mask.hh"
66#include "ED_paint.hh"
67#include "ED_render.hh"
68#include "ED_screen.hh"
69#include "ED_undo.hh"
70#include "ED_util.hh"
71#include "ED_util_imbuf.hh"
72#include "ED_uvedit.hh"
73
74#include "UI_interface.hh"
75#include "UI_resources.hh"
76#include "UI_view2d.hh"
77
78#include "WM_api.hh"
79#include "WM_types.hh"
80
81#include "RE_engine.h"
82
83#include "image_intern.hh"
84
85using blender::Vector;
86
87/* -------------------------------------------------------------------- */
91static void sima_zoom_set(
92 SpaceImage *sima, ARegion *region, float zoom, const float location[2], const bool zoom_to_pos)
93{
94 float oldzoom = sima->zoom;
95 int width, height;
96
97 sima->zoom = zoom;
98
99 if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
100 /* check zoom limits */
101 ED_space_image_get_size(sima, &width, &height);
102
103 width *= sima->zoom;
104 height *= sima->zoom;
105
106 if ((width < 4) && (height < 4) && sima->zoom < oldzoom) {
107 sima->zoom = oldzoom;
108 }
109 else if (BLI_rcti_size_x(&region->winrct) <= sima->zoom) {
110 sima->zoom = oldzoom;
111 }
112 else if (BLI_rcti_size_y(&region->winrct) <= sima->zoom) {
113 sima->zoom = oldzoom;
114 }
115 }
116
117 if (zoom_to_pos && location) {
118 float aspx, aspy, w, h;
119
120 ED_space_image_get_size(sima, &width, &height);
121 ED_space_image_get_aspect(sima, &aspx, &aspy);
122
123 w = width * aspx;
124 h = height * aspy;
125
126 sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
127 sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
128 }
129}
130
132 ARegion *region,
133 float zoomfac,
134 const float location[2],
135 const bool zoom_to_pos)
136{
137 sima_zoom_set(sima, region, sima->zoom * zoomfac, location, zoom_to_pos);
138}
139
143static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *region, const rctf *bounds)
144{
145 int image_size[2];
146 float aspx, aspy;
147
148 ED_space_image_get_size(sima, &image_size[0], &image_size[1]);
149 ED_space_image_get_aspect(sima, &aspx, &aspy);
150
151 image_size[0] = image_size[0] * aspx;
152 image_size[1] = image_size[1] * aspy;
153
154 /* adjust offset and zoom */
155 sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]);
156 sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]);
157
158 float size_xy[2], size;
159 size_xy[0] = BLI_rcti_size_x(&region->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]);
160 size_xy[1] = BLI_rcti_size_y(&region->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]);
161
162 size = min_ff(size_xy[0], size_xy[1]);
163 CLAMP_MAX(size, 100.0f);
164
165 sima_zoom_set(sima, region, size, nullptr, false);
166}
167
169{
170 /* Edit image is set by templates used throughout the interface, so image
171 * operations work outside the image editor. */
172 Image *ima = static_cast<Image *>(CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data);
173
174 if (ima) {
175 return ima;
176 }
177
178 /* Image editor. */
180 return (sima) ? sima->image : nullptr;
181}
182
184{
185 /* Edit image user is set by templates used throughout the interface, so
186 * image operations work outside the image editor. */
187 ImageUser *iuser = static_cast<ImageUser *>(
188 CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data);
189
190 if (iuser) {
191 return iuser;
192 }
193
194 /* Image editor. */
196 return (sima) ? &sima->iuser : nullptr;
197}
198
200{
201 /* Try to get image user from context if available, otherwise use default. */
202 ImageUser *iuser_context = image_user_from_context(C);
203 ImageUser iuser;
204 if (iuser_context) {
205 iuser = *iuser_context;
206 }
207 else {
208 BKE_imageuser_default(&iuser);
209 }
210
211 /* Use the file associated with the active tile. Otherwise use the first tile. */
212 if (ima && ima->source == IMA_SRC_TILED) {
213 const ImageTile *active = (ImageTile *)BLI_findlink(&ima->tiles, ima->active_tile_index);
214 iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number;
215 }
216
217 return iuser;
218}
219
221{
222 Image *ima = image_from_context(C);
224
225 if (ima == nullptr) {
226 return false;
227 }
228
229 void *lock;
230 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
231 const bool has_buffer = (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data));
232 BKE_image_release_ibuf(ima, ibuf, lock);
233 return has_buffer;
234}
235
240{
241 Image *ima = image_from_context(C);
242
243 if (ima && !ID_IS_EDITABLE(&ima->id)) {
244 CTX_wm_operator_poll_msg_set(C, "Image is not editable");
245 return false;
246 }
247
249
250 return BKE_image_has_ibuf(ima, &iuser);
251}
252
254{
255 /* Do not run 'replace' on packed images, it does not give user expected results at all. */
256 Image *ima = image_from_context(C);
257 return (ima && BLI_listbase_is_empty(&ima->packedfiles));
258}
259
260static void image_view_all(SpaceImage *sima, ARegion *region, wmOperator *op)
261{
262 float aspx, aspy, zoomx, zoomy, w, h;
263 int width, height;
264 const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
265
266 ED_space_image_get_size(sima, &width, &height);
267 ED_space_image_get_aspect(sima, &aspx, &aspy);
268
269 w = width * aspx;
270 h = height * aspy;
271
272 float xof = 0.0f, yof = 0.0f;
273 if ((sima->image == nullptr) || (sima->image->source == IMA_SRC_TILED)) {
274 /* Extend the shown area to cover all UDIM tiles. */
275 int x_tiles, y_tiles;
276 if (sima->image == nullptr) {
277 x_tiles = sima->tile_grid_shape[0];
278 y_tiles = sima->tile_grid_shape[1];
279 }
280 else {
281 x_tiles = y_tiles = 1;
283 int tile_x = (tile->tile_number - 1001) % 10;
284 int tile_y = (tile->tile_number - 1001) / 10;
285 x_tiles = max_ii(x_tiles, tile_x + 1);
286 y_tiles = max_ii(y_tiles, tile_y + 1);
287 }
288 }
289 xof = 0.5f * (x_tiles - 1.0f) * w;
290 yof = 0.5f * (y_tiles - 1.0f) * h;
291 w *= x_tiles;
292 h *= y_tiles;
293 }
294
295 /* check if the image will fit in the image with (zoom == 1) */
296 width = BLI_rcti_size_x(&region->winrct) + 1;
297 height = BLI_rcti_size_y(&region->winrct) + 1;
298
299 if (fit_view) {
300 const int margin = 5; /* margin from border */
301
302 zoomx = float(width) / (w + 2 * margin);
303 zoomy = float(height) / (h + 2 * margin);
304
305 sima_zoom_set(sima, region, min_ff(zoomx, zoomy), nullptr, false);
306 }
307 else {
308 if ((w >= width || h >= height) && (width > 0 && height > 0)) {
309 zoomx = float(width) / w;
310 zoomy = float(height) / h;
311
312 /* find the zoom value that will fit the image in the image space */
313 sima_zoom_set(sima, region, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), nullptr, false);
314 }
315 else {
316 sima_zoom_set(sima, region, 1.0f, nullptr, false);
317 }
318 }
319
320 sima->xof = xof;
321 sima->yof = yof;
322}
323
325{
327 // ARegion *region = CTX_wm_region(C); /* XXX. */
328
329 if (sima) {
330 return true; /* XXX (region && region->type->regionid == RGN_TYPE_WINDOW); */
331 }
332 return false;
333}
334
335/* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode or editmode */
337{
339
340 if (sima && (CTX_data_edit_object(C) == nullptr)) {
341 return true;
342 }
343
344 return false;
345}
346
349/* -------------------------------------------------------------------- */
353struct ViewPanData {
354 float x, y;
355 float xof, yof;
356 int launch_event;
357 bool own_cursor;
358};
359
360static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
361{
362 wmWindow *win = CTX_wm_window(C);
364 ViewPanData *vpd;
365
366 op->customdata = vpd = static_cast<ViewPanData *>(
367 MEM_callocN(sizeof(ViewPanData), "ImageViewPanData"));
368
369 /* Grab will be set when running from gizmo. */
370 vpd->own_cursor = (win->grabcursor == 0);
371 if (vpd->own_cursor) {
373 }
374
375 vpd->x = event->xy[0];
376 vpd->y = event->xy[1];
377 vpd->xof = sima->xof;
378 vpd->yof = sima->yof;
380
382}
383
384static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
385{
387 ViewPanData *vpd = static_cast<ViewPanData *>(op->customdata);
388
389 if (cancel) {
390 sima->xof = vpd->xof;
391 sima->yof = vpd->yof;
393 }
394
395 if (vpd->own_cursor) {
397 }
399}
400
402{
404 float offset[2];
405
406 RNA_float_get_array(op->ptr, "offset", offset);
407 sima->xof += offset[0];
408 sima->yof += offset[1];
409
411
412 return OPERATOR_FINISHED;
413}
414
415static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
416{
417 if (event->type == MOUSEPAN) {
419 float offset[2];
420
421 offset[0] = (event->prev_xy[0] - event->xy[0]) / sima->zoom;
422 offset[1] = (event->prev_xy[1] - event->xy[1]) / sima->zoom;
423 RNA_float_set_array(op->ptr, "offset", offset);
424
425 image_view_pan_exec(C, op);
426 return OPERATOR_FINISHED;
427 }
428
429 image_view_pan_init(C, op, event);
431}
432
433static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
434{
436 ViewPanData *vpd = static_cast<ViewPanData *>(op->customdata);
437 float offset[2];
438
439 switch (event->type) {
440 case MOUSEMOVE:
441 sima->xof = vpd->xof;
442 sima->yof = vpd->yof;
443 offset[0] = (vpd->x - event->xy[0]) / sima->zoom;
444 offset[1] = (vpd->y - event->xy[1]) / sima->zoom;
445 RNA_float_set_array(op->ptr, "offset", offset);
446 image_view_pan_exec(C, op);
447 break;
448 default:
449 if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
450 image_view_pan_exit(C, op, false);
451 return OPERATOR_FINISHED;
452 }
453 break;
454 }
455
457}
458
460{
461 image_view_pan_exit(C, op, true);
462}
463
465{
466 /* identifiers */
467 ot->name = "Pan View";
468 ot->idname = "IMAGE_OT_view_pan";
469 ot->description = "Pan the view";
470
471 /* api callbacks */
477
478 /* flags */
480
481 /* properties */
483 "offset",
484 2,
485 nullptr,
486 -FLT_MAX,
487 FLT_MAX,
488 "Offset",
489 "Offset in floating-point units, 1.0 is the width and height of the image",
490 -FLT_MAX,
491 FLT_MAX);
492}
493
496/* -------------------------------------------------------------------- */
500struct ViewZoomData {
501 float origx, origy;
502 float zoom;
503 int launch_event;
504 float location[2];
505
506 /* needed for continuous zoom */
507 wmTimer *timer;
508 double timer_lastdraw;
509 bool own_cursor;
510
511 /* */
514};
515
516static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
517{
518 wmWindow *win = CTX_wm_window(C);
520 ARegion *region = CTX_wm_region(C);
521 ViewZoomData *vpd;
522
523 op->customdata = vpd = static_cast<ViewZoomData *>(
524 MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData"));
525
526 /* Grab will be set when running from gizmo. */
527 vpd->own_cursor = (win->grabcursor == 0);
528 if (vpd->own_cursor) {
530 }
531
532 vpd->origx = event->xy[0];
533 vpd->origy = event->xy[1];
534 vpd->zoom = sima->zoom;
536
538 &region->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
539
540 if (U.viewzoom == USER_ZOOM_CONTINUE) {
541 /* needs a timer to continue redrawing */
544 }
545
546 vpd->sima = sima;
547 vpd->region = region;
548
550}
551
552static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
553{
555 ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
556
557 if (cancel) {
558 sima->zoom = vpd->zoom;
560 }
561
562 if (vpd->timer) {
564 }
565
566 if (vpd->own_cursor) {
568 }
570}
571
573{
575 ARegion *region = CTX_wm_region(C);
576
577 sima_zoom_set_factor(sima, region, RNA_float_get(op->ptr, "factor"), nullptr, false);
578
579 ED_region_tag_redraw(region);
580
581 return OPERATOR_FINISHED;
582}
583
584enum {
588};
589
590static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
591{
592 if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
594 ARegion *region = CTX_wm_region(C);
595 float delta, factor, location[2];
596
598 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
599
600 delta = event->prev_xy[0] - event->xy[0] + event->prev_xy[1] - event->xy[1];
601
602 if (U.uiflag & USER_ZOOM_INVERT) {
603 delta *= -1;
604 }
605
606 factor = 1.0f + delta / 300.0f;
607 RNA_float_set(op->ptr, "factor", factor);
608 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
609 sima_zoom_set(sima,
610 region,
611 sima->zoom * factor,
612 location,
613 (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
614 ED_region_tag_redraw(region);
615
616 return OPERATOR_FINISHED;
617 }
618
619 image_view_zoom_init(C, op, event);
621}
622
624 wmOperator *op,
625 const int x,
626 const int y,
627 const short viewzoom,
628 const short zoom_invert,
629 const bool zoom_to_pos)
630{
631 float factor;
632 float delta;
633
634 if (viewzoom != USER_ZOOM_SCALE) {
635 if (U.uiflag & USER_ZOOM_HORIZ) {
636 delta = float(x - vpd->origx);
637 }
638 else {
639 delta = float(y - vpd->origy);
640 }
641 }
642 else {
643 delta = x - vpd->origx + y - vpd->origy;
644 }
645
646 delta /= U.pixelsize;
647
648 if (zoom_invert) {
649 delta = -delta;
650 }
651
652 if (viewzoom == USER_ZOOM_CONTINUE) {
653 double time = BLI_time_now_seconds();
654 float time_step = float(time - vpd->timer_lastdraw);
655 float zfac;
656 zfac = 1.0f + ((delta / 20.0f) * time_step);
657 vpd->timer_lastdraw = time;
658 /* this is the final zoom, but instead make it into a factor */
659 factor = (vpd->sima->zoom * zfac) / vpd->zoom;
660 }
661 else {
662 factor = 1.0f + delta / 300.0f;
663 }
664
665 RNA_float_set(op->ptr, "factor", factor);
666 sima_zoom_set(vpd->sima, vpd->region, vpd->zoom * factor, vpd->location, zoom_to_pos);
668}
669
670static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
671{
672 ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
673 short event_code = VIEW_PASS;
675
676 /* Execute the events. */
677 if (event->type == MOUSEMOVE) {
678 event_code = VIEW_APPLY;
679 }
680 else if (event->type == TIMER) {
681 /* Continuous zoom. */
682 if (event->customdata == vpd->timer) {
683 event_code = VIEW_APPLY;
684 }
685 }
686 else if (event->type == vpd->launch_event) {
687 if (event->val == KM_RELEASE) {
688 event_code = VIEW_CONFIRM;
689 }
690 }
691
692 switch (event_code) {
693 case VIEW_APPLY: {
694 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
696 op,
697 event->xy[0],
698 event->xy[1],
699 U.viewzoom,
700 (U.uiflag & USER_ZOOM_INVERT) != 0,
701 (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
702 break;
703 }
704 case VIEW_CONFIRM: {
706 break;
707 }
708 }
709
710 if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
711 image_view_zoom_exit(C, op, false);
712 }
713
714 return ret;
715}
716
718{
719 image_view_zoom_exit(C, op, true);
720}
721
723{
724 PropertyRNA *prop;
725
726 /* identifiers */
727 ot->name = "Zoom View";
728 ot->idname = "IMAGE_OT_view_zoom";
729 ot->description = "Zoom in/out the image";
730
731 /* api callbacks */
737
738 /* flags */
740
741 /* properties */
742 prop = RNA_def_float(ot->srna,
743 "factor",
744 0.0f,
745 -FLT_MAX,
746 FLT_MAX,
747 "Factor",
748 "Zoom factor, values higher than 1.0 zoom in, lower values zoom out",
749 -FLT_MAX,
750 FLT_MAX);
752
754}
755
758#ifdef WITH_INPUT_NDOF
759
760/* -------------------------------------------------------------------- */
764/* Combined pan/zoom from a 3D mouse device.
765 * Z zooms, XY pans
766 * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
767 * that explains the negative signs in the code below
768 */
769
770static int image_view_ndof_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
771{
772 if (event->type != NDOF_MOTION) {
773 return OPERATOR_CANCELLED;
774 }
775
777 ARegion *region = CTX_wm_region(C);
778 float pan_vec[3];
779
780 const wmNDOFMotionData *ndof = static_cast<const wmNDOFMotionData *>(event->customdata);
781 const float pan_speed = NDOF_PIXELS_PER_SECOND;
782
783 WM_event_ndof_pan_get(ndof, pan_vec, true);
784
785 mul_v3_fl(pan_vec, ndof->dt);
786 mul_v2_fl(pan_vec, pan_speed / sima->zoom);
787
788 sima_zoom_set_factor(sima, region, max_ff(0.0f, 1.0f - pan_vec[2]), nullptr, false);
789 sima->xof += pan_vec[0];
790 sima->yof += pan_vec[1];
791
792 ED_region_tag_redraw(region);
793
794 return OPERATOR_FINISHED;
795}
796
797void IMAGE_OT_view_ndof(wmOperatorType *ot)
798{
799 /* identifiers */
800 ot->name = "NDOF Pan/Zoom";
801 ot->idname = "IMAGE_OT_view_ndof";
802 ot->description = "Use a 3D mouse device to pan/zoom the view";
803
804 /* api callbacks */
805 ot->invoke = image_view_ndof_invoke;
807
808 /* flags */
810}
811
814#endif /* WITH_INPUT_NDOF */
815
816/* -------------------------------------------------------------------- */
820/* Updates the fields of the View2D member of the SpaceImage struct.
821 * Default behavior is to reset the position of the image and set the zoom to 1
822 * If the image will not fit within the window rectangle, the zoom is adjusted */
823
825{
826 SpaceImage *sima;
827 ARegion *region;
828
829 /* retrieve state */
830 sima = CTX_wm_space_image(C);
831 region = CTX_wm_region(C);
832
833 image_view_all(sima, region, op);
834
835 ED_region_tag_redraw(region);
836
837 return OPERATOR_FINISHED;
838}
839
841{
842 PropertyRNA *prop;
843
844 /* identifiers */
845 ot->name = "Frame All";
846 ot->idname = "IMAGE_OT_view_all";
847 ot->description = "View the entire image";
848
849 /* api callbacks */
852
853 /* flags */
855
856 /* properties */
857 prop = RNA_def_boolean(ot->srna, "fit_view", false, "Fit View", "Fit frame to the viewport");
859}
860
863/* -------------------------------------------------------------------- */
868{
869 SpaceImage *sima;
870 ARegion *region;
871
872 sima = CTX_wm_space_image(C);
873 region = CTX_wm_region(C);
874
875 image_view_all(sima, region, op);
876
877 sima->cursor[0] = 0.5f;
878 sima->cursor[1] = 0.5f;
879
880 /* Needed for updating the cursor. */
882
883 return OPERATOR_FINISHED;
884}
885
887{
888 PropertyRNA *prop;
889
890 /* identifiers */
891 ot->name = "Cursor To Center View";
892 ot->description = "Set 2D Cursor To Center View location";
893 ot->idname = "IMAGE_OT_view_cursor_center";
894
895 /* api callbacks */
898
899 /* properties */
900 prop = RNA_def_boolean(ot->srna, "fit_view", false, "Fit View", "Fit frame to the viewport");
902}
903
906/* -------------------------------------------------------------------- */
911{
913 ARegion *region = CTX_wm_region(C);
914
915 ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]);
916
917 ED_region_tag_redraw(region);
918
919 return OPERATOR_FINISHED;
920}
921
923{
924 /* identifiers */
925 ot->name = "Center View to Cursor";
926 ot->description = "Center the view so that the cursor is in the middle of the view";
927 ot->idname = "IMAGE_OT_view_center_cursor";
928
929 /* api callbacks */
932}
933
936/* -------------------------------------------------------------------- */
941{
942 SpaceImage *sima;
943 ARegion *region;
944 Scene *scene;
945 ViewLayer *view_layer;
946 Object *obedit;
947
948 /* retrieve state */
949 sima = CTX_wm_space_image(C);
950 region = CTX_wm_region(C);
951 scene = CTX_data_scene(C);
952 view_layer = CTX_data_view_layer(C);
953 obedit = CTX_data_edit_object(C);
954
955 /* get bounds */
956 float min[2], max[2];
957 if (ED_space_image_show_uvedit(sima, obedit)) {
959 scene, view_layer, nullptr);
960 bool success = ED_uvedit_minmax_multi(scene, objects, min, max);
961 if (!success) {
962 return OPERATOR_CANCELLED;
963 }
964 }
965 else if (ED_space_image_check_show_maskedit(sima, obedit)) {
966 if (!ED_mask_selected_minmax(C, min, max, false)) {
967 return OPERATOR_CANCELLED;
968 }
969 }
970 rctf bounds{};
971 bounds.xmin = min[0];
972 bounds.ymin = min[1];
973 bounds.xmax = max[0];
974 bounds.ymax = max[1];
975
976 /* add some margin */
977 BLI_rctf_scale(&bounds, 1.4f);
978
979 sima_zoom_set_from_bounds(sima, region, &bounds);
980
981 ED_region_tag_redraw(region);
982
983 return OPERATOR_FINISHED;
984}
985
990
992{
993 /* identifiers */
994 ot->name = "View Center";
995 ot->idname = "IMAGE_OT_view_selected";
996 ot->description = "View all selected UVs";
997
998 /* api callbacks */
1001}
1002
1005/* -------------------------------------------------------------------- */
1010{
1011 SpaceImage *sima = CTX_wm_space_image(C);
1012 ARegion *region = CTX_wm_region(C);
1013 float location[2];
1014
1015 RNA_float_get_array(op->ptr, "location", location);
1016
1018 sima, region, powf(2.0f, 1.0f / 3.0f), location, U.uiflag & USER_ZOOM_TO_MOUSEPOS);
1019
1020 ED_region_tag_redraw(region);
1021
1022 return OPERATOR_FINISHED;
1023}
1024
1025static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1026{
1027 ARegion *region = CTX_wm_region(C);
1028 float location[2];
1029
1031 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1032 RNA_float_set_array(op->ptr, "location", location);
1033
1034 return image_view_zoom_in_exec(C, op);
1035}
1036
1038{
1039 PropertyRNA *prop;
1040
1041 /* identifiers */
1042 ot->name = "Zoom In";
1043 ot->idname = "IMAGE_OT_view_zoom_in";
1044 ot->description = "Zoom in the image (centered around 2D cursor)";
1045
1046 /* api callbacks */
1050
1051 /* flags */
1053
1054 /* properties */
1056 "location",
1057 2,
1058 nullptr,
1059 -FLT_MAX,
1060 FLT_MAX,
1061 "Location",
1062 "Cursor location in screen coordinates",
1063 -10.0f,
1064 10.0f);
1066}
1067
1069{
1070 SpaceImage *sima = CTX_wm_space_image(C);
1071 ARegion *region = CTX_wm_region(C);
1072 float location[2];
1073
1074 RNA_float_get_array(op->ptr, "location", location);
1075
1077 sima, region, powf(0.5f, 1.0f / 3.0f), location, U.uiflag & USER_ZOOM_TO_MOUSEPOS);
1078
1079 ED_region_tag_redraw(region);
1080
1081 return OPERATOR_FINISHED;
1082}
1083
1085{
1086 ARegion *region = CTX_wm_region(C);
1087 float location[2];
1088
1090 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1091 RNA_float_set_array(op->ptr, "location", location);
1092
1093 return image_view_zoom_out_exec(C, op);
1094}
1095
1097{
1098 PropertyRNA *prop;
1099
1100 /* identifiers */
1101 ot->name = "Zoom Out";
1102 ot->idname = "IMAGE_OT_view_zoom_out";
1103 ot->description = "Zoom out the image (centered around 2D cursor)";
1104
1105 /* api callbacks */
1109
1110 /* flags */
1112
1113 /* properties */
1115 "location",
1116 2,
1117 nullptr,
1118 -FLT_MAX,
1119 FLT_MAX,
1120 "Location",
1121 "Cursor location in screen coordinates",
1122 -10.0f,
1123 10.0f);
1125}
1126
1129/* -------------------------------------------------------------------- */
1134{
1135 SpaceImage *sima = CTX_wm_space_image(C);
1136 ARegion *region = CTX_wm_region(C);
1137
1138 sima_zoom_set(sima, region, RNA_float_get(op->ptr, "ratio"), nullptr, false);
1139
1140 /* ensure pixel exact locations for draw */
1141 sima->xof = int(sima->xof);
1142 sima->yof = int(sima->yof);
1143
1144 ED_region_tag_redraw(region);
1145
1146 return OPERATOR_FINISHED;
1147}
1148
1150{
1151 /* identifiers */
1152 ot->name = "View Zoom Ratio";
1153 ot->idname = "IMAGE_OT_view_zoom_ratio";
1154 ot->description = "Set zoom ratio of the view";
1155
1156 /* api callbacks */
1159
1160 /* flags */
1162
1163 /* properties */
1165 "ratio",
1166 0.0f,
1167 -FLT_MAX,
1168 FLT_MAX,
1169 "Ratio",
1170 "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out",
1171 -FLT_MAX,
1172 FLT_MAX);
1173}
1174
1177/* -------------------------------------------------------------------- */
1182{
1183 SpaceImage *sima = CTX_wm_space_image(C);
1184 ARegion *region = CTX_wm_region(C);
1185 rctf bounds;
1186 const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
1187
1189
1191
1192 struct {
1193 float xof;
1194 float yof;
1195 float zoom;
1196 } sima_view_prev{};
1197 sima_view_prev.xof = sima->xof;
1198 sima_view_prev.yof = sima->yof;
1199 sima_view_prev.zoom = sima->zoom;
1200
1201 sima_zoom_set_from_bounds(sima, region, &bounds);
1202
1203 /* zoom out */
1204 if (!zoom_in) {
1205 sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof);
1206 sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof);
1207 sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom);
1208 }
1209
1210 ED_region_tag_redraw(region);
1211
1212 return OPERATOR_FINISHED;
1213}
1214
1216{
1217 /* identifiers */
1218 ot->name = "Zoom to Border";
1219 ot->description = "Zoom in the view to the nearest item contained in the border";
1220 ot->idname = "IMAGE_OT_view_zoom_border";
1221
1222 /* api callbacks */
1227
1229
1230 /* rna */
1232}
1233
1234/* load/replace/save callbacks */
1235static void image_filesel(bContext *C, wmOperator *op, const char *path)
1236{
1237 RNA_string_set(op->ptr, "filepath", path);
1239}
1240
1243/* -------------------------------------------------------------------- */
1252
1254{
1255 ImageOpenData *iod;
1256 op->customdata = iod = MEM_new<ImageOpenData>(__func__);
1257 iod->iuser = static_cast<ImageUser *>(
1258 CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data);
1260}
1261
1262static void image_open_cancel(bContext * /*C*/, wmOperator *op)
1263{
1264 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1265 op->customdata = nullptr;
1266 MEM_delete(iod);
1267}
1268
1270 Library *owner_library,
1271 wmOperator *op,
1272 const ImageFrameRange *range,
1273 const bool use_multiview)
1274{
1275 bool exists = false;
1276 Image *ima = nullptr;
1277
1278 errno = 0;
1279 ima = BKE_image_load_exists_in_lib(bmain, owner_library, range->filepath, &exists);
1280
1281 if (!ima) {
1282 if (op->customdata) {
1283 MEM_delete(static_cast<ImageOpenData *>(op->customdata));
1284 }
1285 BKE_reportf(op->reports,
1286 RPT_ERROR,
1287 "Cannot read '%s': %s",
1288 range->filepath,
1289 errno ? strerror(errno) : RPT_("unsupported image format"));
1290 return nullptr;
1291 }
1292
1293 /* If image already exists, update its file path based on relative path property, see: #109561.
1294 */
1295 if (exists) {
1296 STRNCPY(ima->filepath, range->filepath);
1297 return ima;
1298 }
1299
1300 /* handle multiview images */
1301 if (use_multiview) {
1302 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1303 ImageFormatData *imf = &iod->im_format;
1304
1305 ima->flag |= IMA_USE_VIEWS;
1306 ima->views_format = imf->views_format;
1307 *ima->stereo3d_format = imf->stereo3d_format;
1308 }
1309 else {
1310 ima->flag &= ~IMA_USE_VIEWS;
1312 }
1313
1314 if (ima->source == IMA_SRC_FILE) {
1315 if (range->udims_detected && range->udim_tiles.first) {
1316 ima->source = IMA_SRC_TILED;
1317 ImageTile *first_tile = static_cast<ImageTile *>(ima->tiles.first);
1318 first_tile->tile_number = range->offset;
1319 LISTBASE_FOREACH (LinkData *, node, &range->udim_tiles) {
1320 BKE_image_add_tile(ima, POINTER_AS_INT(node->data), nullptr);
1321 }
1322 }
1323 else if (range->length > 1) {
1324 ima->source = IMA_SRC_SEQUENCE;
1325 }
1326 }
1327
1328 return ima;
1329}
1330
1332{
1333 Main *bmain = CTX_data_main(C);
1334 ScrArea *area = CTX_wm_area(C);
1335 Scene *scene = CTX_data_scene(C);
1336 ImageUser *iuser = nullptr;
1337 Image *ima = nullptr;
1338 int frame_seq_len = 0;
1339 int frame_ofs = 1;
1340
1341 const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
1342 const bool use_udim = RNA_boolean_get(op->ptr, "use_udim_detecting");
1343
1344 if (!op->customdata) {
1345 image_open_init(C, op);
1346 }
1347
1348 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1349 ID *owner_id = iod->pprop.ptr.owner_id;
1350 Library *owner_library = owner_id ? owner_id->lib : nullptr;
1351 blender::StringRefNull root_path = owner_library ? owner_library->runtime.filepath_abs :
1353
1354 ListBase ranges = ED_image_filesel_detect_sequences(root_path, op, use_udim);
1355 LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
1356 Image *ima_range = image_open_single(bmain, owner_library, op, range, use_multiview);
1357
1358 /* take the first image */
1359 if ((ima == nullptr) && ima_range) {
1360 ima = ima_range;
1361 frame_seq_len = range->length;
1362 frame_ofs = range->offset;
1363 }
1364
1365 BLI_freelistN(&range->udim_tiles);
1366 }
1367 BLI_freelistN(&ranges);
1368
1369 if (ima == nullptr) {
1370 return OPERATOR_CANCELLED;
1371 }
1372
1373 /* hook into UI */
1374 if (iod->pprop.prop) {
1375 /* when creating new ID blocks, use is already 1, but RNA
1376 * pointer use also increases user, so this compensates it */
1377 id_us_min(&ima->id);
1378
1379 if (iod->pprop.ptr.owner_id) {
1380 BKE_id_move_to_same_lib(*bmain, ima->id, *iod->pprop.ptr.owner_id);
1381 }
1382
1383 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
1384 RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr, nullptr);
1385 RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1386 }
1387
1388 if (iod->iuser) {
1389 iuser = iod->iuser;
1390 }
1391 else if (area && area->spacetype == SPACE_IMAGE) {
1392 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
1393 ED_space_image_set(bmain, sima, ima, false);
1394 iuser = &sima->iuser;
1395 }
1396 else {
1397 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1398 if (tex && tex->type == TEX_IMAGE) {
1399 iuser = &tex->iuser;
1400 }
1401
1402 if (iuser == nullptr) {
1403 Camera *cam = static_cast<Camera *>(
1404 CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data);
1405 if (cam) {
1406 LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
1407 if (bgpic->ima == ima) {
1408 iuser = &bgpic->iuser;
1409 break;
1410 }
1411 }
1412 }
1413 }
1414 }
1415
1416 /* initialize because of new image */
1417 if (iuser) {
1418 /* If the sequence was a tiled image, we only have one frame. */
1419 iuser->frames = (ima->source == IMA_SRC_SEQUENCE) ? frame_seq_len : 1;
1420 iuser->sfra = 1;
1421 iuser->framenr = 1;
1422 if (ima->source == IMA_SRC_MOVIE) {
1423 iuser->offset = 0;
1424 }
1425 else {
1426 iuser->offset = frame_ofs - 1;
1427 }
1428 iuser->scene = scene;
1429 BKE_image_init_imageuser(ima, iuser);
1430 }
1431
1432 /* XXX BKE_packedfile_unpack_image frees image buffers */
1434
1435 BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
1437
1438 op->customdata = nullptr;
1439 MEM_delete(iod);
1440
1441 return OPERATOR_FINISHED;
1442}
1443
1444static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1445{
1446 SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1447 const char *path = U.textudir;
1448 Image *ima = nullptr;
1449 Scene *scene = CTX_data_scene(C);
1450
1451 if (sima) {
1452 ima = sima->image;
1453 }
1454
1455 if (ima == nullptr) {
1456 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1457 if (tex && tex->type == TEX_IMAGE) {
1458 ima = tex->ima;
1459 }
1460 }
1461
1462 if (ima == nullptr) {
1464 PropertyRNA *prop;
1465
1466 /* hook into UI */
1468
1469 if (prop) {
1470 PointerRNA oldptr;
1471 Image *oldima;
1472
1473 oldptr = RNA_property_pointer_get(&ptr, prop);
1474 oldima = (Image *)oldptr.owner_id;
1475 /* unlikely to fail but better avoid strange crash */
1476 if (oldima && GS(oldima->id.name) == ID_IM) {
1477 ima = oldima;
1478 }
1479 }
1480 }
1481
1482 if (ima) {
1483 path = ima->filepath;
1484 }
1485
1486 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1487 return image_open_exec(C, op);
1488 }
1489
1490 image_open_init(C, op);
1491
1492 /* Show multi-view save options only if scene has multi-views. */
1493 PropertyRNA *prop;
1494 prop = RNA_struct_find_property(op->ptr, "show_multiview");
1495 RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1496
1497 image_filesel(C, op, path);
1498
1500}
1501
1503 PropertyRNA *prop,
1504 void * /*user_data*/)
1505{
1506 const char *prop_id = RNA_property_identifier(prop);
1507
1508 return !STR_ELEM(prop_id, "filepath", "directory", "filename");
1509}
1510
1511static void image_open_draw(bContext * /*C*/, wmOperator *op)
1512{
1513 uiLayout *layout = op->layout;
1514 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1515 ImageFormatData *imf = &iod->im_format;
1516
1517 /* main draw call */
1518 uiDefAutoButsRNA(layout,
1519 op->ptr,
1521 nullptr,
1522 nullptr,
1524 false);
1525
1526 /* image template */
1527 PointerRNA imf_ptr = RNA_pointer_create(nullptr, &RNA_ImageFormatSettings, imf);
1528
1529 /* multiview template */
1530 if (RNA_boolean_get(op->ptr, "show_multiview")) {
1531 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1532 }
1533}
1534
1536{
1538 ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens");
1540}
1541
1543{
1544 /* identifiers */
1545 ot->name = "Open Image";
1546 ot->description = "Open image";
1547 ot->idname = "IMAGE_OT_open";
1548
1549 /* api callbacks */
1554
1555 /* flags */
1557
1558 /* properties */
1568
1570 ot->srna,
1571 "use_sequence_detection",
1572 true,
1573 "Detect Sequences",
1574 "Automatically detect animated sequences in selected images (based on file names)");
1576 "use_udim_detecting",
1577 true,
1578 "Detect UDIMs",
1579 "Detect selected UDIM files and load all matching tiles");
1580}
1581
1584/* -------------------------------------------------------------------- */
1589{
1590 Image *ima = static_cast<Image *>(op->customdata);
1591 if (ima == nullptr) {
1592 return OPERATOR_CANCELLED;
1593 }
1594
1595 char filepath[FILE_MAX];
1596 RNA_string_get(op->ptr, "filepath", filepath);
1597 if (BLI_path_is_rel(filepath)) {
1598 /* Relative path created by the filebrowser are always relative to the current blendfile, need
1599 * to be made relative to the library blendfile path in case image is an editable linked data.
1600 */
1602 /* TODO: make this a BKE_lib_id helper (already a static function in BKE_image too), we likely
1603 * need this in more places in the future. ~~mont29 */
1604 BLI_path_rel(filepath,
1605 ID_IS_LINKED(&ima->id) ? ima->id.lib->runtime.filepath_abs :
1607 }
1608
1609 /* If loading into a tiled texture, ensure that the filename is tokenized. */
1610 if (ima->source == IMA_SRC_TILED) {
1611 BKE_image_ensure_tile_token(filepath, sizeof(filepath));
1612 }
1613
1614 PropertyRNA *imaprop;
1615 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
1616 imaprop = RNA_struct_find_property(&imaptr, "filepath");
1617
1618 RNA_property_string_set(&imaptr, imaprop, filepath);
1619 RNA_property_update(C, &imaptr, imaprop);
1620
1621 return OPERATOR_FINISHED;
1622}
1623
1624static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1625{
1626 Image *ima = image_from_context(C);
1627 if (!ima) {
1628 return OPERATOR_CANCELLED;
1629 }
1630
1631 char filepath[FILE_MAX];
1632 STRNCPY(filepath, ima->filepath);
1633 BLI_path_abs(filepath,
1634 ID_IS_LINKED(&ima->id) ? ima->id.lib->runtime.filepath_abs :
1636
1637 /* Shift+Click to open the file, Alt+Click to browse a folder in the OS's browser. */
1638 if (event->modifier & (KM_SHIFT | KM_ALT)) {
1639 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
1640 PointerRNA props_ptr;
1641
1642 if (event->modifier & KM_ALT) {
1643 char *lslash = (char *)BLI_path_slash_rfind(filepath);
1644 if (lslash) {
1645 *lslash = '\0';
1646 }
1647 }
1648 else if (ima->source == IMA_SRC_TILED) {
1650 BKE_image_user_file_path(&iuser, ima, filepath);
1651 }
1652
1654 RNA_string_set(&props_ptr, "filepath", filepath);
1655 WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr, nullptr);
1656 WM_operator_properties_free(&props_ptr);
1657
1658 return OPERATOR_CANCELLED;
1659 }
1660
1661 /* The image is typically passed to the operator via layout/button context (e.g.
1662 * #uiLayoutSetContextPointer()). The File Browser doesn't support restoring this context
1663 * when calling `exec()` though, so we have to pass it the image via custom data. */
1664 op->customdata = ima;
1665
1666 image_filesel(C, op, filepath);
1667
1669}
1670
1672{
1673 return image_from_context(C) != nullptr;
1674}
1675
1677{
1678 /* identifiers */
1679 ot->name = "Browse Image";
1680 ot->description =
1681 "Open an image file browser, hold Shift to open the file, Alt to browse containing "
1682 "directory";
1683 ot->idname = "IMAGE_OT_file_browse";
1684
1685 /* api callbacks */
1689
1690 /* flags */
1691 ot->flag = OPTYPE_UNDO;
1692
1693 /* properties */
1701}
1702
1705/* -------------------------------------------------------------------- */
1710{
1711 Scene *scene = CTX_data_scene(C);
1712 Image *ima = image_from_context(C);
1714
1715 if (!ima || !iuser) {
1716 /* Try to get a Texture, or a SpaceImage from context... */
1717 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1718 if (tex && tex->type == TEX_IMAGE) {
1719 ima = tex->ima;
1720 iuser = &tex->iuser;
1721 }
1722 }
1723
1724 if (!ima || !iuser || !BKE_image_has_anim(ima)) {
1725 return OPERATOR_CANCELLED;
1726 }
1727
1728 ImBufAnim *anim = ((ImageAnim *)ima->anims.first)->anim;
1729 if (!anim) {
1730 return OPERATOR_CANCELLED;
1731 }
1733 BKE_image_user_frame_calc(ima, iuser, scene->r.cfra);
1734
1735 return OPERATOR_FINISHED;
1736}
1737
1739{
1740 /* identifiers */
1741 ot->name = "Match Movie Length";
1742 ot->description = "Set image's user's length to the one of this video";
1743 ot->idname = "IMAGE_OT_match_movie_length";
1744
1745 /* api callbacks */
1747
1748 /* flags */
1749 /* Don't think we need undo for that. */
1750 ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
1751}
1752
1755/* -------------------------------------------------------------------- */
1760{
1761 Main *bmain = CTX_data_main(C);
1762 SpaceImage *sima = CTX_wm_space_image(C);
1763 char filepath[FILE_MAX];
1764
1765 if (!sima->image) {
1766 return OPERATOR_CANCELLED;
1767 }
1768
1769 RNA_string_get(op->ptr, "filepath", filepath);
1770
1771 /* we can't do much if the filepath is longer than FILE_MAX :/ */
1772 STRNCPY(sima->image->filepath, filepath);
1773
1774 if (sima->image->source == IMA_SRC_GENERATED) {
1775 sima->image->source = IMA_SRC_FILE;
1776 BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1777 }
1778
1780 sima->image->source = IMA_SRC_MOVIE;
1781 }
1782 else {
1783 sima->image->source = IMA_SRC_FILE;
1784 }
1785
1786 /* XXX BKE_packedfile_unpack_image frees image buffers */
1788
1790 BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1791 DEG_id_tag_update(&sima->image->id, 0);
1793
1794 return OPERATOR_FINISHED;
1795}
1796
1797static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1798{
1799 SpaceImage *sima = CTX_wm_space_image(C);
1800
1801 if (!sima->image) {
1802 return OPERATOR_CANCELLED;
1803 }
1804
1805 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1806 return image_replace_exec(C, op);
1807 }
1808
1809 if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
1810 RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->filepath));
1811 }
1812
1813 image_filesel(C, op, sima->image->filepath);
1814
1816}
1817
1819{
1820 /* identifiers */
1821 ot->name = "Replace Image";
1822 ot->idname = "IMAGE_OT_replace";
1823 ot->description = "Replace current image by another one from disk";
1824
1825 /* api callbacks */
1829
1830 /* flags */
1832
1833 /* properties */
1841}
1842
1845/* -------------------------------------------------------------------- */
1854
1856{
1857 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1858 RNA_string_get(op->ptr, "filepath", opts->filepath);
1860 }
1861
1862 opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") &&
1863 RNA_boolean_get(op->ptr, "relative_path"));
1864 opts->save_copy = (RNA_struct_find_property(op->ptr, "copy") &&
1865 RNA_boolean_get(op->ptr, "copy"));
1866 opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
1867 RNA_boolean_get(op->ptr, "save_as_render"));
1868}
1869
1870static bool save_image_op(
1871 Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, const ImageSaveOptions *opts)
1872{
1873 WM_cursor_wait(true);
1874
1875 bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
1876
1877 WM_cursor_wait(false);
1878
1879 /* Remember file path for next save. */
1880 STRNCPY(G.filepath_last_image, opts->filepath);
1881
1883
1884 return ok;
1885}
1886
1888{
1889 Main *bmain = CTX_data_main(C);
1890 Image *image = image_from_context(C);
1892 Scene *scene = CTX_data_scene(C);
1893
1894 ImageSaveData *isd = static_cast<ImageSaveData *>(MEM_callocN(sizeof(*isd), __func__));
1895 isd->image = image;
1896 isd->iuser = iuser;
1897
1898 if (!BKE_image_save_options_init(&isd->opts, bmain, scene, image, iuser, true, false)) {
1900 MEM_freeN(isd);
1901 return nullptr;
1902 }
1903
1904 isd->opts.do_newpath = true;
1905
1906 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
1907 RNA_string_set(op->ptr, "filepath", isd->opts.filepath);
1908 }
1909
1910 /* Enable save_copy by default for render results. */
1911 if (image->source == IMA_SRC_VIEWER && !RNA_struct_property_is_set(op->ptr, "copy")) {
1912 RNA_boolean_set(op->ptr, "copy", true);
1913 }
1914
1915 if (!RNA_struct_property_is_set(op->ptr, "save_as_render")) {
1916 RNA_boolean_set(op->ptr, "save_as_render", isd->opts.save_as_render);
1917 }
1918
1919 /* Show multi-view save options only if image has multi-views. */
1920 PropertyRNA *prop;
1921 prop = RNA_struct_find_property(op->ptr, "show_multiview");
1923 prop = RNA_struct_find_property(op->ptr, "use_multiview");
1925
1926 op->customdata = isd;
1927
1928 return isd;
1929}
1930
1932{
1933 if (op->customdata) {
1934 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
1936
1937 MEM_freeN(op->customdata);
1938 op->customdata = nullptr;
1939 }
1940}
1941
1943{
1944 Main *bmain = CTX_data_main(C);
1945 ImageSaveData *isd;
1946
1947 if (op->customdata) {
1948 isd = static_cast<ImageSaveData *>(op->customdata);
1949 }
1950 else {
1951 isd = image_save_as_init(C, op);
1952 if (isd == nullptr) {
1953 return OPERATOR_CANCELLED;
1954 }
1955 }
1956
1957 image_save_options_from_op(bmain, &isd->opts, op);
1959
1960 save_image_op(bmain, isd->image, isd->iuser, op, &isd->opts);
1961
1962 if (isd->opts.save_copy == false) {
1964 }
1965
1967
1968 return OPERATOR_FINISHED;
1969}
1970
1972{
1973 Main *bmain = CTX_data_main(C);
1974 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
1975
1976 image_save_options_from_op(bmain, &isd->opts, op);
1978
1980}
1981
1982static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1983{
1984 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1985 return image_save_as_exec(C, op);
1986 }
1987
1988 ImageSaveData *isd = image_save_as_init(C, op);
1989 if (isd == nullptr) {
1990 return OPERATOR_CANCELLED;
1991 }
1992
1993 image_filesel(C, op, isd->opts.filepath);
1994
1996}
1997
1999{
2001}
2002
2003static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *user_data)
2004{
2005 ImageSaveData *isd = static_cast<ImageSaveData *>(user_data);
2006 const char *prop_id = RNA_property_identifier(prop);
2007
2008 return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
2009 STREQ(prop_id, "filename") ||
2010 /* when saving a copy, relative path has no effect */
2011 (STREQ(prop_id, "relative_path") && RNA_boolean_get(ptr, "copy")) ||
2012 (STREQ(prop_id, "save_as_render") && isd->image->source == IMA_SRC_VIEWER));
2013}
2014
2015static void image_save_as_draw(bContext * /*C*/, wmOperator *op)
2016{
2017 uiLayout *layout = op->layout;
2018 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
2019 const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
2020 const bool save_as_render = RNA_boolean_get(op->ptr, "save_as_render");
2021
2022 uiLayoutSetPropSep(layout, true);
2023 uiLayoutSetPropDecorate(layout, false);
2024
2025 /* Operator settings. */
2026 uiDefAutoButsRNA(layout,
2027 op->ptr,
2029 isd,
2030 nullptr,
2032 false);
2033
2034 uiItemS(layout);
2035
2036 /* Image format settings. */
2037 PointerRNA imf_ptr = RNA_pointer_create(nullptr, &RNA_ImageFormatSettings, &isd->opts.im_format);
2038 uiTemplateImageSettings(layout, &imf_ptr, save_as_render);
2039
2040 if (!save_as_render) {
2041 PointerRNA linear_settings_ptr = RNA_pointer_get(&imf_ptr, "linear_colorspace_settings");
2042 uiLayout *col = uiLayoutColumn(layout, true);
2043 uiItemS(col);
2044 uiItemR(col, &linear_settings_ptr, "name", UI_ITEM_NONE, IFACE_("Color Space"), ICON_NONE);
2045 }
2046
2047 /* Multiview settings. */
2048 if (is_multiview) {
2049 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
2050 }
2051}
2052
2054{
2056 return false;
2057 }
2058
2059 if (G.is_rendering) {
2060 /* no need to nullptr check here */
2061 Image *ima = image_from_context(C);
2062
2063 if (ima->source == IMA_SRC_VIEWER) {
2064 CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
2065 return false;
2066 }
2067 }
2068
2069 return true;
2070}
2071
2073{
2074 /* identifiers */
2075 ot->name = "Save As Image";
2076 ot->idname = "IMAGE_OT_save_as";
2077 ot->description = "Save the image with another name and/or settings";
2078
2079 /* api callbacks */
2086
2087 /* flags */
2089
2090 /* properties */
2091 PropertyRNA *prop;
2092 prop = RNA_def_boolean(
2093 ot->srna,
2094 "save_as_render",
2095 false,
2096 "Save As Render",
2097 "Save image with render color management.\n"
2098 "For display image formats like PNG, apply view and display transform.\n"
2099 "For intermediate image formats like OpenEXR, use the default render output color space");
2101 prop = RNA_def_boolean(ot->srna,
2102 "copy",
2103 false,
2104 "Copy",
2105 "Create a new image file without modifying the current image in Blender");
2107
2112 FILE_SAVE,
2116}
2117
2120/* -------------------------------------------------------------------- */
2128{
2129 void *lock;
2130 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
2131 bool ret = false;
2132
2133 if (ibuf && BKE_image_buffer_format_writable(ibuf)) {
2134 ret = true;
2135 }
2136
2137 BKE_image_release_ibuf(ima, ibuf, lock);
2138 return ret;
2139}
2140
2142{
2143 /* Can't save if there are no pixels. */
2144 if (image_from_context_has_data_poll(C) == false) {
2145 return false;
2146 }
2147
2148 /* Check if there is a valid file path and image format we can write
2149 * outside of the 'poll' so we can show a report with a pop-up. */
2150
2151 /* Can always repack images.
2152 * Images without a filepath will go to "Save As". */
2153 return true;
2154}
2155
2157{
2158 Main *bmain = CTX_data_main(C);
2159 Image *image = image_from_context(C);
2161 Scene *scene = CTX_data_scene(C);
2162 ImageSaveOptions opts;
2163 bool ok = false;
2164
2165 if (BKE_image_has_packedfile(image)) {
2166 /* Save packed files to memory. */
2167 BKE_image_memorypack(image);
2168 /* Report since this can be called from key shortcuts. */
2169 BKE_reportf(op->reports, RPT_INFO, "Packed to memory image \"%s\"", image->filepath);
2170 return OPERATOR_FINISHED;
2171 }
2172
2173 if (!BKE_image_save_options_init(&opts, bmain, scene, image, iuser, false, false)) {
2175 return OPERATOR_CANCELLED;
2176 }
2177 image_save_options_from_op(bmain, &opts, op);
2178
2179 /* Check if file write permission is ok. */
2180 if (BLI_exists(opts.filepath) && !BLI_file_is_writable(opts.filepath)) {
2182 op->reports, RPT_ERROR, "Cannot save image, path \"%s\" is not writable", opts.filepath);
2183 }
2184 else if (save_image_op(bmain, image, iuser, op, &opts)) {
2185 /* Report since this can be called from key shortcuts. */
2186 BKE_reportf(op->reports, RPT_INFO, "Saved image \"%s\"", opts.filepath);
2187 ok = true;
2188 }
2189
2191
2192 if (ok) {
2193 return OPERATOR_FINISHED;
2194 }
2195
2196 return OPERATOR_CANCELLED;
2197}
2198
2199static int image_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2200{
2201 Image *ima = image_from_context(C);
2203
2204 /* Not writable formats or images without a file-path will go to "Save As". */
2205 if (!BKE_image_has_packedfile(ima) &&
2206 (!BKE_image_has_filepath(ima) || !image_file_format_writable(ima, iuser)))
2207 {
2208 WM_operator_name_call(C, "IMAGE_OT_save_as", WM_OP_INVOKE_DEFAULT, nullptr, event);
2209 return OPERATOR_CANCELLED;
2210 }
2211 return image_save_exec(C, op);
2212}
2213
2215{
2216 /* identifiers */
2217 ot->name = "Save Image";
2218 ot->idname = "IMAGE_OT_save";
2219 ot->description = "Save the image with current name and settings";
2220
2221 /* api callbacks */
2225
2226 /* flags */
2228}
2229
2232/* -------------------------------------------------------------------- */
2237{
2238 Image *image = image_from_context(C);
2239 ImBuf *ibuf, *first_ibuf = nullptr;
2240 int tot = 0;
2241 char di[FILE_MAX];
2242 MovieCacheIter *iter;
2243
2244 if (image == nullptr) {
2245 return OPERATOR_CANCELLED;
2246 }
2247
2248 if (image->source != IMA_SRC_SEQUENCE) {
2249 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2250 return OPERATOR_CANCELLED;
2251 }
2252
2253 if (image->type == IMA_TYPE_MULTILAYER) {
2254 BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2255 return OPERATOR_CANCELLED;
2256 }
2257
2258 /* get total dirty buffers and first dirty buffer which is used for menu */
2259 ibuf = nullptr;
2260 if (image->cache != nullptr) {
2261 iter = IMB_moviecacheIter_new(image->cache);
2262 while (!IMB_moviecacheIter_done(iter)) {
2263 ibuf = IMB_moviecacheIter_getImBuf(iter);
2264 if (ibuf != nullptr && ibuf->userflags & IB_BITMAPDIRTY) {
2265 if (first_ibuf == nullptr) {
2266 first_ibuf = ibuf;
2267 }
2268 tot++;
2269 }
2271 }
2273 }
2274
2275 if (tot == 0) {
2276 BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2277 return OPERATOR_CANCELLED;
2278 }
2279
2280 /* get a filename for menu */
2281 BLI_path_split_dir_part(first_ibuf->filepath, di, sizeof(di));
2282 BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2283
2284 iter = IMB_moviecacheIter_new(image->cache);
2285 while (!IMB_moviecacheIter_done(iter)) {
2286 ibuf = IMB_moviecacheIter_getImBuf(iter);
2287
2288 if (ibuf != nullptr && ibuf->userflags & IB_BITMAPDIRTY) {
2289 if (0 == IMB_saveiff(ibuf, ibuf->filepath, IB_rect)) {
2290 BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
2291 break;
2292 }
2293
2294 BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->filepath);
2295 ibuf->userflags &= ~IB_BITMAPDIRTY;
2296 }
2297
2299 }
2301
2302 return OPERATOR_FINISHED;
2303}
2304
2306{
2307 /* identifiers */
2308 ot->name = "Save Sequence";
2309 ot->idname = "IMAGE_OT_save_sequence";
2310 ot->description = "Save a sequence of images";
2311
2312 /* api callbacks */
2315
2316 /* flags */
2318}
2319
2322/* -------------------------------------------------------------------- */
2330
2331static bool image_should_be_saved(Image *ima, bool *r_is_format_writable)
2332{
2333 if (BKE_image_is_dirty_writable(ima, r_is_format_writable) &&
2335 {
2337 }
2338 return false;
2339}
2340
2342{
2343 return strchr(ima->filepath, '\\') || strchr(ima->filepath, '/');
2344}
2345
2347{
2348 /* Images without a filepath (implied with IMA_SRC_GENERATED) should
2349 * be packed during a save_all operation. */
2350 return (ima->source == IMA_SRC_GENERATED) ||
2351 (ima->source == IMA_SRC_TILED && !BKE_image_has_filepath(ima));
2352}
2353
2355{
2356 ReportList reports;
2357 BKE_reports_init(&reports, RPT_STORE);
2358
2359 uint modified_images_count = ED_image_save_all_modified_info(bmain, &reports);
2360 bool should_save = modified_images_count || !BLI_listbase_is_empty(&reports.list);
2361
2362 BKE_reports_free(&reports);
2363
2364 return should_save;
2365}
2366
2368{
2369 GSet *unique_paths = BLI_gset_str_new(__func__);
2370
2371 int num_saveable_images = 0;
2372
2373 for (Image *ima = static_cast<Image *>(bmain->images.first); ima;
2374 ima = static_cast<Image *>(ima->id.next))
2375 {
2376 bool is_format_writable;
2377
2378 if (image_should_be_saved(ima, &is_format_writable)) {
2380 if (ID_IS_EDITABLE(ima)) {
2381 num_saveable_images++;
2382 }
2383 else {
2384 BKE_reportf(reports,
2386 "Packed library image can't be saved: \"%s\" from \"%s\"",
2387 ima->id.name + 2,
2388 ima->id.lib->filepath);
2389 }
2390 }
2391 else if (!is_format_writable) {
2392 BKE_reportf(reports,
2394 "Image can't be saved, use a different file format: \"%s\"",
2395 ima->id.name + 2);
2396 }
2397 else {
2398 if (image_has_valid_path(ima)) {
2399 num_saveable_images++;
2400 if (BLI_gset_haskey(unique_paths, ima->filepath)) {
2401 BKE_reportf(reports,
2403 "Multiple images can't be saved to an identical path: \"%s\"",
2404 ima->filepath);
2405 }
2406 else {
2407 BLI_gset_insert(unique_paths, BLI_strdup(ima->filepath));
2408 }
2409 }
2410 else {
2411 BKE_reportf(reports,
2413 "Image can't be saved, no valid file path: \"%s\"",
2414 ima->filepath);
2415 }
2416 }
2417 }
2418 }
2419
2420 BLI_gset_free(unique_paths, MEM_freeN);
2421 return num_saveable_images;
2422}
2423
2425{
2426 Main *bmain = CTX_data_main(C);
2427
2428 ED_image_save_all_modified_info(bmain, reports);
2429
2430 bool ok = true;
2431
2432 for (Image *ima = static_cast<Image *>(bmain->images.first); ima;
2433 ima = static_cast<Image *>(ima->id.next))
2434 {
2435 bool is_format_writable;
2436
2437 if (image_should_be_saved(ima, &is_format_writable)) {
2440 }
2441 else if (is_format_writable) {
2442 if (image_has_valid_path(ima)) {
2443 ImageSaveOptions opts;
2444 Scene *scene = CTX_data_scene(C);
2445 if (BKE_image_save_options_init(&opts, bmain, scene, ima, nullptr, false, false)) {
2446 bool saved_successfully = BKE_image_save(reports, bmain, ima, nullptr, &opts);
2447 ok = ok && saved_successfully;
2448 }
2450 }
2451 }
2452 }
2453 }
2454 return ok;
2455}
2456
2458{
2459 int num_files = ED_image_save_all_modified_info(CTX_data_main(C), nullptr);
2460 return num_files > 0;
2461}
2462
2468
2470{
2471 /* identifiers */
2472 ot->name = "Save All Modified";
2473 ot->idname = "IMAGE_OT_save_all_modified";
2474 ot->description = "Save all modified images";
2475
2476 /* api callbacks */
2479
2480 /* flags */
2482}
2483
2486/* -------------------------------------------------------------------- */
2490static int image_reload_exec(bContext *C, wmOperator * /*op*/)
2491{
2492 Main *bmain = CTX_data_main(C);
2493 Image *ima = image_from_context(C);
2495
2496 if (!ima) {
2497 return OPERATOR_CANCELLED;
2498 }
2499
2500 /* XXX BKE_packedfile_unpack_image frees image buffers */
2502
2503 BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
2504 DEG_id_tag_update(&ima->id, 0);
2505
2507
2508 return OPERATOR_FINISHED;
2509}
2510
2512{
2513 /* identifiers */
2514 ot->name = "Reload Image";
2515 ot->idname = "IMAGE_OT_reload";
2516 ot->description = "Reload current image from disk";
2517
2518 /* api callbacks */
2520
2521 /* flags */
2522 ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2523}
2524
2527/* -------------------------------------------------------------------- */
2531#define IMA_DEF_NAME N_("Untitled")
2532
2533enum {
2537};
2538
2542
2544{
2545 if (op->customdata) {
2546 return static_cast<ImageNewData *>(op->customdata);
2547 }
2548
2549 ImageNewData *data = static_cast<ImageNewData *>(MEM_callocN(sizeof(ImageNewData), __func__));
2550 UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2551 op->customdata = data;
2552 return data;
2553}
2554
2556{
2558}
2559
2561{
2562 SpaceImage *sima;
2563 Image *ima;
2564 Main *bmain;
2565 PropertyRNA *prop;
2566 char name_buffer[MAX_ID_NAME - 2];
2567 const char *name;
2568 float color[4];
2569 int width, height, floatbuf, gen_type, alpha;
2570 int stereo3d;
2571
2572 /* retrieve state */
2573 sima = CTX_wm_space_image(C);
2574 bmain = CTX_data_main(C);
2575
2576 prop = RNA_struct_find_property(op->ptr, "name");
2577 RNA_property_string_get(op->ptr, prop, name_buffer);
2578 if (!RNA_property_is_set(op->ptr, prop)) {
2579 /* Default value, we can translate! */
2580 name = DATA_(name_buffer);
2581 }
2582 else {
2583 name = name_buffer;
2584 }
2585 width = RNA_int_get(op->ptr, "width");
2586 height = RNA_int_get(op->ptr, "height");
2587 floatbuf = RNA_boolean_get(op->ptr, "float");
2588 gen_type = RNA_enum_get(op->ptr, "generated_type");
2589 RNA_float_get_array(op->ptr, "color", color);
2590 alpha = RNA_boolean_get(op->ptr, "alpha");
2591 stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2592 bool tiled = RNA_boolean_get(op->ptr, "tiled");
2593
2594 if (!alpha) {
2595 color[3] = 1.0f;
2596 }
2597
2598 ima = BKE_image_add_generated(bmain,
2599 width,
2600 height,
2601 name,
2602 alpha ? 32 : 24,
2603 floatbuf,
2604 gen_type,
2605 color,
2606 stereo3d,
2607 false,
2608 tiled);
2609
2610 if (!ima) {
2611 image_new_free(op);
2612 return OPERATOR_CANCELLED;
2613 }
2614
2615 /* hook into UI */
2616 ImageNewData *data = image_new_init(C, op);
2617
2618 if (data->pprop.prop) {
2619 /* when creating new ID blocks, use is already 1, but RNA
2620 * pointer use also increases user, so this compensates it */
2621 id_us_min(&ima->id);
2622
2623 if (data->pprop.ptr.owner_id) {
2624 BKE_id_move_to_same_lib(*bmain, ima->id, *data->pprop.ptr.owner_id);
2625 }
2626
2627 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
2628 RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr, nullptr);
2629 RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2630 }
2631 else if (sima) {
2632 ED_space_image_set(bmain, sima, ima, false);
2633 }
2634 else {
2635 /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to
2636 * anything. ref. #94599. */
2637 id_us_min(&ima->id);
2638 }
2639
2640 BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE);
2641
2643
2644 image_new_free(op);
2645
2646 return OPERATOR_FINISHED;
2647}
2648
2649static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
2650{
2651 /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2653 op->customdata = data = static_cast<ImageNewData *>(MEM_callocN(sizeof(ImageNewData), __func__));
2654 UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2655
2656 /* Better for user feedback. */
2657 RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2659 C, op, 300, IFACE_("Create a New Image"), IFACE_("New Image"));
2660}
2661
2662static void image_new_draw(bContext * /*C*/, wmOperator *op)
2663{
2664 uiLayout *col;
2665 uiLayout *layout = op->layout;
2666#if 0
2667 Scene *scene = CTX_data_scene(C);
2668 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2669#endif
2670
2671 /* copy of WM_operator_props_dialog_popup() layout */
2672
2673 uiLayoutSetPropSep(layout, true);
2674 uiLayoutSetPropDecorate(layout, false);
2675
2676 col = uiLayoutColumn(layout, false);
2677 uiItemR(col, op->ptr, "name", UI_ITEM_NONE, nullptr, ICON_NONE);
2678 uiItemR(col, op->ptr, "width", UI_ITEM_NONE, nullptr, ICON_NONE);
2679 uiItemR(col, op->ptr, "height", UI_ITEM_NONE, nullptr, ICON_NONE);
2680 uiItemR(col, op->ptr, "color", UI_ITEM_NONE, nullptr, ICON_NONE);
2681 uiItemR(col, op->ptr, "alpha", UI_ITEM_NONE, nullptr, ICON_NONE);
2682 uiItemR(col, op->ptr, "generated_type", UI_ITEM_NONE, nullptr, ICON_NONE);
2683 uiItemR(col, op->ptr, "float", UI_ITEM_NONE, nullptr, ICON_NONE);
2684 uiItemR(col, op->ptr, "tiled", UI_ITEM_NONE, nullptr, ICON_NONE);
2685
2686#if 0
2687 if (is_multiview) {
2688 uiItemL(col[0], "", ICON_NONE);
2689 uiItemR(col[1], op->ptr, "use_stereo_3d", 0, nullptr, ICON_NONE);
2690 }
2691#endif
2692}
2693
2694static void image_new_cancel(bContext * /*C*/, wmOperator *op)
2695{
2696 image_new_free(op);
2697}
2698
2700{
2701 PropertyRNA *prop;
2702 static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2703
2704 /* identifiers */
2705 ot->name = "New Image";
2706 ot->description = "Create a new image";
2707 ot->idname = "IMAGE_OT_new";
2708
2709 /* api callbacks */
2712 ot->ui = image_new_draw;
2714
2715 /* flags */
2716 ot->flag = OPTYPE_UNDO;
2717
2718 /* properties */
2720 ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2721 prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2723 prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2725 prop = RNA_def_float_color(
2726 ot->srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2728 RNA_def_property_float_array_default(prop, default_color);
2729 RNA_def_boolean(ot->srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
2731 "generated_type",
2734 "Generated Type",
2735 "Fill the image with a grid for UV map testing");
2737 "float",
2738 false,
2739 "32-bit Float",
2740 "Create image with 32-bit floating-point bit depth");
2742 prop = RNA_def_boolean(
2743 ot->srna, "use_stereo_3d", false, "Stereo 3D", "Create an image with left and right views");
2745 prop = RNA_def_boolean(ot->srna, "tiled", false, "Tiled", "Create a tiled image");
2747}
2748
2749#undef IMA_DEF_NAME
2750
2753/* -------------------------------------------------------------------- */
2758{
2759 Image *ima = image_from_context(C);
2761 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
2762 SpaceImage *sima = CTX_wm_space_image(C);
2763 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
2764
2765 if (ibuf == nullptr) {
2766 /* TODO: this should actually never happen, but does for render-results -> cleanup. */
2767 return OPERATOR_CANCELLED;
2768 }
2769
2770 const bool use_flip_x = RNA_boolean_get(op->ptr, "use_flip_x");
2771 const bool use_flip_y = RNA_boolean_get(op->ptr, "use_flip_y");
2772
2773 if (!use_flip_x && !use_flip_y) {
2774 BKE_image_release_ibuf(ima, ibuf, nullptr);
2775 return OPERATOR_FINISHED;
2776 }
2777
2778 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
2779
2780 if (is_paint) {
2782 }
2783
2784 const int size_x = ibuf->x;
2785 const int size_y = ibuf->y;
2786
2787 if (ibuf->float_buffer.data) {
2788 float *float_pixels = ibuf->float_buffer.data;
2789
2790 float *orig_float_pixels = static_cast<float *>(MEM_dupallocN(float_pixels));
2791 for (int x = 0; x < size_x; x++) {
2792 const int source_pixel_x = use_flip_x ? size_x - x - 1 : x;
2793 for (int y = 0; y < size_y; y++) {
2794 const int source_pixel_y = use_flip_y ? size_y - y - 1 : y;
2795
2796 const float *source_pixel =
2797 &orig_float_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
2798 float *target_pixel = &float_pixels[4 * (x + y * size_x)];
2799
2800 copy_v4_v4(target_pixel, source_pixel);
2801 }
2802 }
2803 MEM_freeN(orig_float_pixels);
2804
2805 if (ibuf->byte_buffer.data) {
2806 IMB_rect_from_float(ibuf);
2807 }
2808 }
2809 else if (ibuf->byte_buffer.data) {
2810 uchar *char_pixels = ibuf->byte_buffer.data;
2811 uchar *orig_char_pixels = static_cast<uchar *>(MEM_dupallocN(char_pixels));
2812 for (int x = 0; x < size_x; x++) {
2813 const int source_pixel_x = use_flip_x ? size_x - x - 1 : x;
2814 for (int y = 0; y < size_y; y++) {
2815 const int source_pixel_y = use_flip_y ? size_y - y - 1 : y;
2816
2817 const uchar *source_pixel =
2818 &orig_char_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
2819 uchar *target_pixel = &char_pixels[4 * (x + y * size_x)];
2820
2821 copy_v4_v4_uchar(target_pixel, source_pixel);
2822 }
2823 }
2824 MEM_freeN(orig_char_pixels);
2825 }
2826 else {
2827 BKE_image_release_ibuf(ima, ibuf, nullptr);
2828 return OPERATOR_CANCELLED;
2829 }
2830
2832 BKE_image_mark_dirty(ima, ibuf);
2833
2834 if (ibuf->mipmap[0]) {
2836 }
2837
2839
2841
2844
2845 BKE_image_release_ibuf(ima, ibuf, nullptr);
2846
2847 return OPERATOR_FINISHED;
2848}
2849
2851{
2852 /* identifiers */
2853 ot->name = "Flip Image";
2854 ot->idname = "IMAGE_OT_flip";
2855 ot->description = "Flip the image";
2856
2857 /* api callbacks */
2860
2861 /* properties */
2862 PropertyRNA *prop;
2863 prop = RNA_def_boolean(
2864 ot->srna, "use_flip_x", false, "Horizontal", "Flip the image horizontally");
2866 prop = RNA_def_boolean(ot->srna, "use_flip_y", false, "Vertical", "Flip the image vertically");
2868
2869 /* flags */
2871}
2872
2875/* -------------------------------------------------------------------- */
2880{
2881 Image *ima = image_from_context(C);
2883 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
2884 SpaceImage *sima = CTX_wm_space_image(C);
2885 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
2886
2887 if (ibuf == nullptr) {
2888 /* TODO: this should actually never happen, but does for render-results -> cleanup. */
2889 return OPERATOR_CANCELLED;
2890 }
2891
2892 int degrees = RNA_enum_get(op->ptr, "degrees");
2893
2894 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
2895
2896 if (is_paint) {
2898 }
2899
2900 if (!IMB_rotate_orthogonal(ibuf, degrees)) {
2901 BKE_image_release_ibuf(ima, ibuf, nullptr);
2902 return OPERATOR_CANCELLED;
2903 }
2904
2906 BKE_image_mark_dirty(ima, ibuf);
2907
2908 if (ibuf->mipmap[0]) {
2910 }
2911
2913
2915
2917
2919 BKE_image_release_ibuf(ima, ibuf, nullptr);
2920
2921 return OPERATOR_FINISHED;
2922}
2923
2925{
2926 static const EnumPropertyItem orthogonal_rotation_items[] = {
2927 {90, "90", 0, "90 Degrees", "Rotate 90 degrees clockwise"},
2928 {180, "180", 0, "180 Degrees", "Rotate 180 degrees clockwise"},
2929 {270, "270", 0, "270 Degrees", "Rotate 270 degrees clockwise"},
2930 {0, nullptr, 0, nullptr, nullptr},
2931 };
2932
2933 /* identifiers */
2934 ot->name = "Rotate Image Orthogonal";
2935 ot->idname = "IMAGE_OT_rotate_orthogonal";
2936 ot->description = "Rotate the image";
2937
2938 /* api callbacks */
2941
2942 /* properties */
2943 PropertyRNA *prop;
2944 prop = RNA_def_enum(ot->srna,
2945 "degrees",
2946 orthogonal_rotation_items,
2947 90,
2948 "Degrees",
2949 "Amount of rotation in degrees (90, 180, 270)");
2951
2952 /* flags */
2954}
2955
2958/* -------------------------------------------------------------------- */
2963{
2964 Image *ima = image_from_context(C);
2965 if (ima == nullptr) {
2966 return false;
2967 }
2968
2969 if (G.is_rendering && ima->source == IMA_SRC_VIEWER) {
2970 BKE_report(op->reports, RPT_ERROR, "Images cannot be copied while rendering");
2971 return false;
2972 }
2973
2975 WM_cursor_wait(true);
2976 void *lock;
2977 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
2978 bool changed = false;
2979 if (ibuf) {
2980 if (WM_clipboard_image_set(ibuf)) {
2981 changed = true;
2982 }
2983 }
2984 BKE_image_release_ibuf(ima, ibuf, lock);
2985 WM_cursor_wait(false);
2986
2987 return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2988}
2989
2991{
2993 CTX_wm_operator_poll_msg_set(C, "No images available");
2994 return false;
2995 }
2996
2997 return true;
2998}
2999
3001{
3002 /* identifiers */
3003 ot->name = "Copy Image";
3004 ot->idname = "IMAGE_OT_clipboard_copy";
3005 ot->description = "Copy the image to the clipboard";
3006
3007 /* api callbacks */
3010
3011 /* flags */
3013}
3014
3017/* -------------------------------------------------------------------- */
3022{
3023 bool changed = false;
3024
3025 WM_cursor_wait(true);
3026 ImBuf *ibuf = WM_clipboard_image_get();
3027 if (ibuf) {
3028 ED_undo_push_op(C, op);
3029
3030 Main *bmain = CTX_data_main(C);
3031 SpaceImage *sima = CTX_wm_space_image(C);
3032 Image *ima = BKE_image_add_from_imbuf(bmain, ibuf, "Clipboard");
3033 IMB_freeImBuf(ibuf);
3034
3035 ED_space_image_set(bmain, sima, ima, false);
3036 BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE);
3038 changed = true;
3039 }
3040 WM_cursor_wait(false);
3041
3042 return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3043}
3044
3046{
3047 SpaceImage *sima = CTX_wm_space_image(C);
3048 if (!sima) {
3049 CTX_wm_operator_poll_msg_set(C, "Image Editor not found");
3050 return false;
3051 }
3052
3054 CTX_wm_operator_poll_msg_set(C, "No compatible images are on the clipboard");
3055 return false;
3056 }
3057
3058 return true;
3059}
3060
3062{
3063 /* identifiers */
3064 ot->name = "Paste Image";
3065 ot->idname = "IMAGE_OT_clipboard_paste";
3066 ot->description = "Paste new image from the clipboard";
3067
3068 /* api callbacks */
3071
3072 /* flags */
3074}
3075
3078/* -------------------------------------------------------------------- */
3083{
3084 Image *ima = image_from_context(C);
3086 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3087 SpaceImage *sima = CTX_wm_space_image(C);
3088 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
3089
3090 /* flags indicate if this channel should be inverted */
3091 const bool r = RNA_boolean_get(op->ptr, "invert_r");
3092 const bool g = RNA_boolean_get(op->ptr, "invert_g");
3093 const bool b = RNA_boolean_get(op->ptr, "invert_b");
3094 const bool a = RNA_boolean_get(op->ptr, "invert_a");
3095
3096 size_t i;
3097
3098 if (ibuf == nullptr) {
3099 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3100 return OPERATOR_CANCELLED;
3101 }
3102
3103 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
3104
3105 if (is_paint) {
3107 }
3108
3109 /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
3110 if (ibuf->float_buffer.data) {
3111
3112 float *fp = ibuf->float_buffer.data;
3113 for (i = size_t(ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
3114 if (r) {
3115 fp[0] = 1.0f - fp[0];
3116 }
3117 if (g) {
3118 fp[1] = 1.0f - fp[1];
3119 }
3120 if (b) {
3121 fp[2] = 1.0f - fp[2];
3122 }
3123 if (a) {
3124 fp[3] = 1.0f - fp[3];
3125 }
3126 }
3127
3128 if (ibuf->byte_buffer.data) {
3129 IMB_rect_from_float(ibuf);
3130 }
3131 }
3132 else if (ibuf->byte_buffer.data) {
3133
3134 uchar *cp = ibuf->byte_buffer.data;
3135 for (i = size_t(ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
3136 if (r) {
3137 cp[0] = 255 - cp[0];
3138 }
3139 if (g) {
3140 cp[1] = 255 - cp[1];
3141 }
3142 if (b) {
3143 cp[2] = 255 - cp[2];
3144 }
3145 if (a) {
3146 cp[3] = 255 - cp[3];
3147 }
3148 }
3149 }
3150 else {
3151 BKE_image_release_ibuf(ima, ibuf, nullptr);
3152 return OPERATOR_CANCELLED;
3153 }
3154
3156 BKE_image_mark_dirty(ima, ibuf);
3157
3158 if (ibuf->mipmap[0]) {
3160 }
3161
3163
3165
3167
3169
3170 BKE_image_release_ibuf(ima, ibuf, nullptr);
3171
3172 return OPERATOR_FINISHED;
3173}
3174
3176{
3177 PropertyRNA *prop;
3178
3179 /* identifiers */
3180 ot->name = "Invert Channels";
3181 ot->idname = "IMAGE_OT_invert";
3182 ot->description = "Invert image's channels";
3183
3184 /* api callbacks */
3187
3188 /* properties */
3189 prop = RNA_def_boolean(ot->srna, "invert_r", false, "Red", "Invert red channel");
3191 prop = RNA_def_boolean(ot->srna, "invert_g", false, "Green", "Invert green channel");
3193 prop = RNA_def_boolean(ot->srna, "invert_b", false, "Blue", "Invert blue channel");
3195 prop = RNA_def_boolean(ot->srna, "invert_a", false, "Alpha", "Invert alpha channel");
3197
3198 /* flags */
3200}
3201
3204/* -------------------------------------------------------------------- */
3208static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
3209{
3210 Image *ima = image_from_context(C);
3212 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3213 if (!RNA_property_is_set(op->ptr, prop)) {
3214 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3215 const int size[2] = {ibuf->x, ibuf->y};
3216 RNA_property_int_set_array(op->ptr, prop, size);
3217 BKE_image_release_ibuf(ima, ibuf, nullptr);
3218 }
3220 C, op, 200, IFACE_("Scale Image to New Size"), IFACE_("Resize"));
3221}
3222
3224{
3225 Image *ima = image_from_context(C);
3227 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3228 SpaceImage *sima = CTX_wm_space_image(C);
3229 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
3230
3231 if (ibuf == nullptr) {
3232 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3233 return OPERATOR_CANCELLED;
3234 }
3235
3236 if (is_paint) {
3238 }
3239
3240 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3241 int size[2];
3242 if (RNA_property_is_set(op->ptr, prop)) {
3243 RNA_property_int_get_array(op->ptr, prop, size);
3244 }
3245 else {
3246 size[0] = ibuf->x;
3247 size[1] = ibuf->y;
3248 RNA_property_int_set_array(op->ptr, prop, size);
3249 }
3250
3251 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
3252
3254 IMB_scale(ibuf, size[0], size[1], IMBScaleFilter::Box, false);
3255 BKE_image_mark_dirty(ima, ibuf);
3256 BKE_image_release_ibuf(ima, ibuf, nullptr);
3257
3259
3261
3262 DEG_id_tag_update(&ima->id, 0);
3264
3265 return OPERATOR_FINISHED;
3266}
3267
3269{
3270 /* identifiers */
3271 ot->name = "Resize Image";
3272 ot->idname = "IMAGE_OT_resize";
3273 ot->description = "Resize the image";
3274
3275 /* api callbacks */
3279
3280 /* properties */
3281 RNA_def_int_vector(ot->srna, "size", 2, nullptr, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
3282
3283 /* flags */
3285}
3286
3289/* -------------------------------------------------------------------- */
3294{
3295 Image *ima = image_from_context(C);
3296
3297 if (!ima) {
3298 return false;
3299 }
3300
3302 BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
3303 return false;
3304 }
3305
3306 return true;
3307}
3308
3310{
3311 Main *bmain = CTX_data_main(C);
3312 Image *ima = image_from_context(C);
3313
3314 if (!image_pack_test(C, op)) {
3315 return OPERATOR_CANCELLED;
3316 }
3317
3318 if (BKE_image_is_dirty(ima)) {
3320 }
3321 else {
3322 BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
3323 }
3324
3326
3327 return OPERATOR_FINISHED;
3328}
3329
3331{
3332 /* identifiers */
3333 ot->name = "Pack Image";
3334 ot->description = "Pack an image as embedded data into the .blend file";
3335 ot->idname = "IMAGE_OT_pack";
3336
3337 /* api callbacks */
3339
3340 /* flags */
3342}
3343
3346/* -------------------------------------------------------------------- */
3351{
3352 Main *bmain = CTX_data_main(C);
3353 Image *ima = image_from_context(C);
3354 int method = RNA_enum_get(op->ptr, "method");
3355
3356 /* find the supplied image by name */
3357 if (RNA_struct_property_is_set(op->ptr, "id")) {
3358 char imaname[MAX_ID_NAME - 2];
3359 RNA_string_get(op->ptr, "id", imaname);
3360 ima = static_cast<Image *>(BLI_findstring(&bmain->images, imaname, offsetof(ID, name) + 2));
3361 if (!ima) {
3362 ima = image_from_context(C);
3363 }
3364 }
3365
3366 if (!ima || !BKE_image_has_packedfile(ima)) {
3367 return OPERATOR_CANCELLED;
3368 }
3369
3370 if (!ID_IS_EDITABLE(&ima->id)) {
3371 BKE_report(op->reports, RPT_ERROR, "Image is not editable");
3372 return OPERATOR_CANCELLED;
3373 }
3374
3376 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
3377 return OPERATOR_CANCELLED;
3378 }
3379
3380 if (G.fileflags & G_FILE_AUTOPACK) {
3381 BKE_report(op->reports,
3383 "AutoPack is enabled, so image will be packed again on file save");
3384 }
3385
3386 /* XXX BKE_packedfile_unpack_image frees image buffers */
3388
3390
3392
3393 return OPERATOR_FINISHED;
3394}
3395
3396static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
3397{
3398 Image *ima = image_from_context(C);
3399
3400 if (RNA_struct_property_is_set(op->ptr, "id")) {
3401 return image_unpack_exec(C, op);
3402 }
3403
3404 if (!ima || !BKE_image_has_packedfile(ima)) {
3405 return OPERATOR_CANCELLED;
3406 }
3407
3408 if (!ID_IS_EDITABLE(&ima->id)) {
3409 BKE_report(op->reports, RPT_ERROR, "Image is not editable");
3410 return OPERATOR_CANCELLED;
3411 }
3412
3414 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
3415 return OPERATOR_CANCELLED;
3416 }
3417
3418 if (G.fileflags & G_FILE_AUTOPACK) {
3419 BKE_report(op->reports,
3421 "AutoPack is enabled, so image will be packed again on file save");
3422 }
3423
3424 unpack_menu(C,
3425 "IMAGE_OT_unpack",
3426 ima->id.name + 2,
3427 ima->filepath,
3428 "textures",
3430 ((ImagePackedFile *)ima->packedfiles.first)->packedfile :
3431 nullptr);
3432
3433 return OPERATOR_FINISHED;
3434}
3435
3437{
3438 /* identifiers */
3439 ot->name = "Unpack Image";
3440 ot->description = "Save an image packed in the .blend file to disk";
3441 ot->idname = "IMAGE_OT_unpack";
3442
3443 /* api callbacks */
3446
3447 /* flags */
3449
3450 /* properties */
3452 ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
3453 /* XXX, weak!, will fail with library, name collisions */
3455 ot->srna, "id", nullptr, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
3456}
3457
3460/* -------------------------------------------------------------------- */
3465 ARegion *region,
3466 const int mval[2],
3467 float r_fpos[2])
3468{
3469 void *lock;
3470 ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
3471
3472 if (ibuf == nullptr) {
3474 return false;
3475 }
3476
3477 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &r_fpos[0], &r_fpos[1]);
3478
3480 return true;
3481}
3482
3484 SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
3485{
3486 if (r_is_data) {
3487 *r_is_data = false;
3488 }
3489 if (sima->image == nullptr) {
3490 return false;
3491 }
3492 float uv[2];
3493 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &uv[0], &uv[1]);
3494 int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, nullptr);
3495
3496 void *lock;
3498 bool ret = false;
3499
3500 if (ibuf == nullptr) {
3502 return false;
3503 }
3504
3505 if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
3506 const float *fp;
3507 uchar *cp;
3508 int x = int(uv[0] * ibuf->x), y = int(uv[1] * ibuf->y);
3509
3510 CLAMP(x, 0, ibuf->x - 1);
3511 CLAMP(y, 0, ibuf->y - 1);
3512
3513 if (ibuf->float_buffer.data) {
3514 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
3515 copy_v3_v3(r_col, fp);
3516 ret = true;
3517 }
3518 else if (ibuf->byte_buffer.data) {
3519 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
3520 rgb_uchar_to_float(r_col, cp);
3522 ret = true;
3523 }
3524 }
3525
3526 if (r_is_data) {
3527 *r_is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
3528 }
3529
3531 return ret;
3532}
3533
3535{
3536 /* identifiers */
3537 ot->name = "Sample Color";
3538 ot->idname = "IMAGE_OT_sample";
3539 ot->description = "Use mouse to sample a color in current image";
3540
3541 /* api callbacks */
3546
3547 /* flags */
3549
3550 PropertyRNA *prop;
3551 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3554}
3555
3558/* -------------------------------------------------------------------- */
3563{
3564 SpaceImage *sima = CTX_wm_space_image(C);
3565 ARegion *region = CTX_wm_region(C);
3566 Scene *scene = CTX_data_scene(C);
3567 Image *ima = ED_space_image(sima);
3568
3569 int x_start = RNA_int_get(op->ptr, "xstart");
3570 int y_start = RNA_int_get(op->ptr, "ystart");
3571 int x_end = RNA_int_get(op->ptr, "xend");
3572 int y_end = RNA_int_get(op->ptr, "yend");
3573
3574 float uv1[2], uv2[2], ofs[2];
3575 UI_view2d_region_to_view(&region->v2d, x_start, y_start, &uv1[0], &uv1[1]);
3576 UI_view2d_region_to_view(&region->v2d, x_end, y_end, &uv2[0], &uv2[1]);
3577
3578 /* If the image has tiles, shift the positions accordingly. */
3579 int tile = BKE_image_get_tile_from_pos(ima, uv1, uv1, ofs);
3580 sub_v2_v2(uv2, ofs);
3581
3582 void *lock;
3584 Histogram *hist = &sima->sample_line_hist;
3585
3586 if (ibuf == nullptr) {
3588 return OPERATOR_CANCELLED;
3589 }
3590 /* hmmmm */
3591 if (ibuf->channels < 3) {
3593 return OPERATOR_CANCELLED;
3594 }
3595
3596 copy_v2_v2(hist->co[0], uv1);
3597 copy_v2_v2(hist->co[1], uv2);
3598
3599 /* enable line drawing */
3600 hist->flag |= HISTO_FLAG_SAMPLELINE;
3601
3602 BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
3603
3604 /* reset y zoom */
3605 hist->ymax = 1.0f;
3606
3608
3610
3611 return OPERATOR_FINISHED;
3612}
3613
3614static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3615{
3616 SpaceImage *sima = CTX_wm_space_image(C);
3617
3618 Histogram *hist = &sima->sample_line_hist;
3619 hist->flag &= ~HISTO_FLAG_SAMPLELINE;
3620
3621 if (!ED_space_image_has_buffer(sima)) {
3622 return OPERATOR_CANCELLED;
3623 }
3624
3625 return WM_gesture_straightline_invoke(C, op, event);
3626}
3627
3629{
3630 /* identifiers */
3631 ot->name = "Sample Line";
3632 ot->idname = "IMAGE_OT_sample_line";
3633 ot->description = "Sample a line and show it in Scope panels";
3634
3635 /* api callbacks */
3641
3642 /* flags */
3643 ot->flag = 0; /* no undo/register since this operates on the space */
3644
3646}
3647
3650/* -------------------------------------------------------------------- */
3655{
3656 static const EnumPropertyItem point_items[] = {
3657 {0, "BLACK_POINT", 0, "Black Point", ""},
3658 {1, "WHITE_POINT", 0, "White Point", ""},
3659 {0, nullptr, 0, nullptr, nullptr},
3660 };
3661
3662 /* identifiers */
3663 ot->name = "Set Curves Point";
3664 ot->idname = "IMAGE_OT_curves_point_set";
3665 ot->description = "Set black point or white point for curves";
3666
3667 /* flags */
3669
3670 /* api callbacks */
3675
3676 /* properties */
3678 ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3679
3680 PropertyRNA *prop;
3681 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3684}
3685
3688/* -------------------------------------------------------------------- */
3693{
3694 Image *ima = image_from_context(C);
3695
3696 return (ima && ima->type == IMA_TYPE_R_RESULT);
3697}
3698
3700{
3701 Image *ima = image_from_context(C);
3702 const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
3703
3704 if (!ED_image_slot_cycle(ima, direction)) {
3705 return OPERATOR_CANCELLED;
3706 }
3707
3708 WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, nullptr);
3709
3710 /* no undo push for browsing existing */
3712 if ((slot && slot->render) || ima->render_slot == ima->last_render_slot) {
3713 return OPERATOR_CANCELLED;
3714 }
3715
3716 return OPERATOR_FINISHED;
3717}
3718
3720{
3721 /* identifiers */
3722 ot->name = "Cycle Render Slot";
3723 ot->idname = "IMAGE_OT_cycle_render_slot";
3724 ot->description = "Cycle through all non-void render slots";
3725
3726 /* api callbacks */
3729
3730 /* flags */
3732
3733 RNA_def_boolean(ot->srna, "reverse", false, "Cycle in Reverse", "");
3734}
3735
3738/* -------------------------------------------------------------------- */
3743{
3744 Image *ima = image_from_context(C);
3746
3747 if (!BKE_image_clear_renderslot(ima, iuser, ima->render_slot)) {
3748 return OPERATOR_CANCELLED;
3749 }
3750
3751 WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, nullptr);
3752
3753 return OPERATOR_FINISHED;
3754}
3755
3757{
3758 /* identifiers */
3759 ot->name = "Clear Render Slot";
3760 ot->idname = "IMAGE_OT_clear_render_slot";
3761 ot->description = "Clear the currently selected render slot";
3762
3763 /* api callbacks */
3766
3767 /* flags */
3769}
3770
3773/* -------------------------------------------------------------------- */
3778{
3779 Image *ima = image_from_context(C);
3780
3781 RenderSlot *slot = BKE_image_add_renderslot(ima, nullptr);
3782 ima->render_slot = BLI_findindex(&ima->renderslots, slot);
3783
3784 WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, nullptr);
3785
3786 return OPERATOR_FINISHED;
3787}
3788
3790{
3791 /* identifiers */
3792 ot->name = "Add Render Slot";
3793 ot->idname = "IMAGE_OT_add_render_slot";
3794 ot->description = "Add a new render slot";
3795
3796 /* api callbacks */
3799
3800 /* flags */
3802}
3803
3806/* -------------------------------------------------------------------- */
3811{
3812 Image *ima = image_from_context(C);
3814
3815 if (!BKE_image_remove_renderslot(ima, iuser, ima->render_slot)) {
3816 return OPERATOR_CANCELLED;
3817 }
3818
3819 WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, nullptr);
3820
3821 return OPERATOR_FINISHED;
3822}
3823
3825{
3826 /* identifiers */
3827 ot->name = "Remove Render Slot";
3828 ot->idname = "IMAGE_OT_remove_render_slot";
3829 ot->description = "Remove the current render slot";
3830
3831 /* api callbacks */
3834
3835 /* flags */
3837}
3838
3841/* -------------------------------------------------------------------- */
3846{
3847 /* prevent changes during render */
3848 if (G.is_rendering) {
3849 return false;
3850 }
3851
3853}
3854
3856{
3857 Scene *scene = CTX_data_scene(C);
3858
3859 /* set the new frame number */
3860 scene->r.cfra = RNA_int_get(op->ptr, "frame");
3861 FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
3862 scene->r.subframe = 0.0f;
3863
3864 /* do updates */
3867}
3868
3870{
3871 change_frame_apply(C, op);
3872
3873 return OPERATOR_FINISHED;
3874}
3875
3876static int frame_from_event(bContext *C, const wmEvent *event)
3877{
3878 ARegion *region = CTX_wm_region(C);
3879 Scene *scene = CTX_data_scene(C);
3880 int framenr = 0;
3881
3882 if (region->regiontype == RGN_TYPE_WINDOW) {
3883 float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
3884
3885 framenr = sfra + event->mval[0] / framelen;
3886 }
3887 else {
3888 float viewx, viewy;
3889
3890 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
3891
3892 framenr = round_fl_to_int(viewx);
3893 }
3894
3895 return framenr;
3896}
3897
3898static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3899{
3900 ARegion *region = CTX_wm_region(C);
3901
3902 if (region->regiontype == RGN_TYPE_WINDOW) {
3903 const SpaceImage *sima = CTX_wm_space_image(C);
3904 if (!ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
3905 return OPERATOR_PASS_THROUGH;
3906 }
3907 }
3908
3909 RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3910
3911 change_frame_apply(C, op);
3912
3913 /* add temp handler */
3915
3917}
3918
3919static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
3920{
3921 switch (event->type) {
3922 case EVT_ESCKEY:
3923 return OPERATOR_FINISHED;
3924
3925 case MOUSEMOVE:
3926 RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3927 change_frame_apply(C, op);
3928 break;
3929
3930 case LEFTMOUSE:
3931 case RIGHTMOUSE:
3932 if (event->val == KM_RELEASE) {
3933 return OPERATOR_FINISHED;
3934 }
3935 break;
3936 }
3937
3939}
3940
3942{
3943 /* identifiers */
3944 ot->name = "Change Frame";
3945 ot->idname = "IMAGE_OT_change_frame";
3946 ot->description = "Interactively change the current frame number";
3947
3948 /* api callbacks */
3953
3954 /* flags */
3956
3957 /* rna */
3958 RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
3959}
3960
3961/* Reload cached render results... */
3962/* goes over all scenes, reads render layers */
3964{
3965 Main *bmain = CTX_data_main(C);
3966 Scene *scene = CTX_data_scene(C);
3967 SpaceImage *sima = CTX_wm_space_image(C);
3968 Image *ima;
3969
3970 ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
3971 if (sima->image == nullptr) {
3972 ED_space_image_set(bmain, sima, ima, false);
3973 }
3974
3975 RE_ReadRenderResult(scene, scene);
3976
3978 return OPERATOR_FINISHED;
3979}
3980
3982{
3983 ot->name = "Open Cached Render";
3984 ot->idname = "IMAGE_OT_read_viewlayers";
3985 ot->description = "Read all the current scene's view layers from cache, as needed";
3986
3989
3990 /* flags */
3991 ot->flag = 0;
3992}
3993
3996/* -------------------------------------------------------------------- */
4001{
4002 ARegion *region = CTX_wm_region(C);
4003 Scene *scene = CTX_data_scene(C);
4004 Render *re = RE_GetSceneRender(scene);
4005 SpaceImage *sima = CTX_wm_space_image(C);
4006
4007 if (re == nullptr) {
4008 /* Shouldn't happen, but better be safe close to the release. */
4009 return OPERATOR_CANCELLED;
4010 }
4011
4012 /* Get information about the previous render, or current scene if no render yet. */
4013 int width, height;
4014 BKE_render_resolution(&scene->r, false, &width, &height);
4016 &scene->r;
4017
4018 /* Get rectangle from the operator. */
4019 rctf border;
4021 UI_view2d_region_to_view_rctf(&region->v2d, &border, &border);
4022
4023 /* Adjust for cropping. */
4024 if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
4025 border.xmin = rd->border.xmin + border.xmin * (rd->border.xmax - rd->border.xmin);
4026 border.xmax = rd->border.xmin + border.xmax * (rd->border.xmax - rd->border.xmin);
4027 border.ymin = rd->border.ymin + border.ymin * (rd->border.ymax - rd->border.ymin);
4028 border.ymax = rd->border.ymin + border.ymax * (rd->border.ymax - rd->border.ymin);
4029 }
4030
4031 CLAMP(border.xmin, 0.0f, 1.0f);
4032 CLAMP(border.ymin, 0.0f, 1.0f);
4033 CLAMP(border.xmax, 0.0f, 1.0f);
4034 CLAMP(border.ymax, 0.0f, 1.0f);
4035
4036 /* Drawing a border surrounding the entire camera view switches off border rendering
4037 * or the border covers no pixels. */
4038 if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
4039 (border.xmin == border.xmax || border.ymin == border.ymax))
4040 {
4041 scene->r.mode &= ~R_BORDER;
4042 }
4043 else {
4044 /* Snap border to pixel boundaries, so drawing a border within a pixel selects that pixel. */
4045 border.xmin = floorf(border.xmin * width) / width;
4046 border.xmax = ceilf(border.xmax * width) / width;
4047 border.ymin = floorf(border.ymin * height) / height;
4048 border.ymax = ceilf(border.ymax * height) / height;
4049
4050 /* Set border. */
4051 scene->r.border = border;
4052 scene->r.mode |= R_BORDER;
4053 }
4054
4057
4058 return OPERATOR_FINISHED;
4059}
4060
4062{
4063 /* identifiers */
4064 ot->name = "Render Region";
4065 ot->description = "Set the boundaries of the render region and enable render region";
4066 ot->idname = "IMAGE_OT_render_border";
4067
4068 /* api callbacks */
4074
4075 /* flags */
4077
4078 /* rna */
4080}
4081
4084/* -------------------------------------------------------------------- */
4089{
4090 Scene *scene = CTX_data_scene(C);
4091 scene->r.mode &= ~R_BORDER;
4093 BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
4094 return OPERATOR_FINISHED;
4095}
4096
4098{
4099 /* identifiers */
4100 ot->name = "Clear Render Region";
4101 ot->description = "Clear the boundaries of the render region and disable render region";
4102 ot->idname = "IMAGE_OT_clear_render_border";
4103
4104 /* api callbacks */
4107
4108 /* flags */
4110}
4111
4114/* -------------------------------------------------------------------- */
4119{
4120 RNA_float_get_array(ptr, "color", tile->gen_color);
4121 tile->gen_type = RNA_enum_get(ptr, "generated_type");
4122 tile->gen_x = RNA_int_get(ptr, "width");
4123 tile->gen_y = RNA_int_get(ptr, "height");
4124 bool is_float = RNA_boolean_get(ptr, "float");
4125
4126 tile->gen_flag = is_float ? IMA_GEN_FLOAT : 0;
4127 tile->gen_depth = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
4128
4129 return BKE_image_fill_tile(ima, tile);
4130}
4131
4133{
4134 uiLayoutSetPropSep(layout, true);
4135 uiLayoutSetPropDecorate(layout, false);
4136
4137 uiLayout *col = uiLayoutColumn(layout, false);
4138 uiItemR(col, ptr, "color", UI_ITEM_NONE, nullptr, ICON_NONE);
4139 uiItemR(col, ptr, "width", UI_ITEM_NONE, nullptr, ICON_NONE);
4140 uiItemR(col, ptr, "height", UI_ITEM_NONE, nullptr, ICON_NONE);
4141 uiItemR(col, ptr, "alpha", UI_ITEM_NONE, nullptr, ICON_NONE);
4142 uiItemR(col, ptr, "generated_type", UI_ITEM_NONE, nullptr, ICON_NONE);
4143 uiItemR(col, ptr, "float", UI_ITEM_NONE, nullptr, ICON_NONE);
4144}
4145
4147{
4148 ImageUser iuser;
4149 BKE_imageuser_default(&iuser);
4150 if (tile != nullptr) {
4151 iuser.tile = tile->tile_number;
4152 }
4153
4154 /* Acquire ibuf to get the default values.
4155 * If the specified tile has no ibuf, try acquiring the main tile instead
4156 * (unless the specified tile already was the first tile). */
4157 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
4158 if (ibuf == nullptr && (tile != nullptr) && (tile != ima->tiles.first)) {
4159 ibuf = BKE_image_acquire_ibuf(ima, nullptr, nullptr);
4160 }
4161
4162 if (ibuf != nullptr) {
4163 /* Initialize properties from reference tile. */
4164 RNA_int_set(ptr, "width", ibuf->x);
4165 RNA_int_set(ptr, "height", ibuf->y);
4166 RNA_boolean_set(ptr, "float", ibuf->float_buffer.data != nullptr);
4167 RNA_boolean_set(ptr, "alpha", ibuf->planes > 24);
4168
4169 BKE_image_release_ibuf(ima, ibuf, nullptr);
4170 }
4171}
4172
4174{
4175 PropertyRNA *prop;
4176 static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
4177 prop = RNA_def_float_color(
4178 srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
4180 RNA_def_property_float_array_default(prop, default_color);
4181 RNA_def_enum(srna,
4182 "generated_type",
4185 "Generated Type",
4186 "Fill the image with a grid for UV map testing");
4187 prop = RNA_def_int(srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
4189 prop = RNA_def_int(srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
4191
4192 /* Only needed when filling the first tile. */
4194 srna, "float", false, "32-bit Float", "Create image with 32-bit floating-point bit depth");
4195 RNA_def_boolean(srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
4196}
4197
4199{
4200 Image *ima = CTX_data_edit_image(C);
4201
4202 return (ima != nullptr && ima->source == IMA_SRC_TILED && BKE_image_has_ibuf(ima, nullptr));
4203}
4204
4206{
4207 Image *ima = CTX_data_edit_image(C);
4208
4209 int start_tile = RNA_int_get(op->ptr, "number");
4210 int end_tile = start_tile + RNA_int_get(op->ptr, "count") - 1;
4211
4212 if (start_tile < 1001 || end_tile > IMA_UDIM_MAX) {
4213 BKE_report(op->reports, RPT_ERROR, "Invalid UDIM index range was specified");
4214 return OPERATOR_CANCELLED;
4215 }
4216
4217 bool fill_tile = RNA_boolean_get(op->ptr, "fill");
4218 char *label = RNA_string_get_alloc(op->ptr, "label", nullptr, 0, nullptr);
4219
4220 /* BKE_image_add_tile assumes a pre-sorted list of tiles. */
4222
4223 ImageTile *last_tile_created = nullptr;
4224 for (int tile_number = start_tile; tile_number <= end_tile; tile_number++) {
4225 ImageTile *tile = BKE_image_add_tile(ima, tile_number, label);
4226
4227 if (tile != nullptr) {
4228 if (fill_tile) {
4229 do_fill_tile(op->ptr, ima, tile);
4230 }
4231
4232 last_tile_created = tile;
4233 }
4234 }
4236
4237 if (!last_tile_created) {
4238 BKE_report(op->reports, RPT_WARNING, "No UDIM tiles were created");
4239 return OPERATOR_CANCELLED;
4240 }
4241
4242 ima->active_tile_index = BLI_findindex(&ima->tiles, last_tile_created);
4243
4244 WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, nullptr);
4245 return OPERATOR_FINISHED;
4246}
4247
4248static int tile_add_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
4249{
4250 Image *ima = CTX_data_edit_image(C);
4251
4252 /* Find the first gap in tile numbers or the number after the last if
4253 * no gap exists. */
4254 int next_number = 0;
4255 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
4256 next_number = tile->tile_number + 1;
4257 if (tile->next == nullptr || tile->next->tile_number > next_number) {
4258 break;
4259 }
4260 }
4261
4262 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4263 tile_fill_init(op->ptr, ima, tile);
4264
4265 RNA_int_set(op->ptr, "number", next_number);
4266 RNA_int_set(op->ptr, "count", 1);
4267 RNA_string_set(op->ptr, "label", "");
4268
4270 op,
4271 300,
4272 IFACE_("Add Tile to Image"),
4274}
4275
4276static void tile_add_draw(bContext * /*C*/, wmOperator *op)
4277{
4278 uiLayout *col;
4279 uiLayout *layout = op->layout;
4280
4281 uiLayoutSetPropSep(layout, true);
4282 uiLayoutSetPropDecorate(layout, false);
4283
4284 col = uiLayoutColumn(layout, false);
4285 uiItemR(col, op->ptr, "number", UI_ITEM_NONE, nullptr, ICON_NONE);
4286 uiItemR(col, op->ptr, "count", UI_ITEM_NONE, nullptr, ICON_NONE);
4287 uiItemR(col, op->ptr, "label", UI_ITEM_NONE, nullptr, ICON_NONE);
4288 uiItemR(layout, op->ptr, "fill", UI_ITEM_NONE, nullptr, ICON_NONE);
4289
4290 if (RNA_boolean_get(op->ptr, "fill")) {
4291 draw_fill_tile(op->ptr, layout);
4292 }
4293}
4294
4296{
4297 /* identifiers */
4298 ot->name = "Add Tile";
4299 ot->description = "Adds a tile to the image";
4300 ot->idname = "IMAGE_OT_tile_add";
4301
4302 /* api callbacks */
4306 ot->ui = tile_add_draw;
4307
4308 /* flags */
4310
4312 "number",
4313 1002,
4314 1001,
4316 "Number",
4317 "UDIM number of the tile",
4318 1001,
4319 1099);
4320 RNA_def_int(ot->srna, "count", 1, 1, INT_MAX, "Count", "How many tiles to add", 1, 1000);
4321 RNA_def_string(ot->srna, "label", nullptr, 0, "Label", "Optional tile label");
4322 RNA_def_boolean(ot->srna, "fill", true, "Fill", "Fill new tile with a generated image");
4324}
4325
4328/* -------------------------------------------------------------------- */
4333{
4334 Image *ima = CTX_data_edit_image(C);
4335
4336 return (ima != nullptr && ima->source == IMA_SRC_TILED && !BLI_listbase_is_single(&ima->tiles));
4337}
4338
4339static int tile_remove_exec(bContext *C, wmOperator * /*op*/)
4340{
4341 Image *ima = CTX_data_edit_image(C);
4342
4343 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4344 if (!BKE_image_remove_tile(ima, tile)) {
4345 return OPERATOR_CANCELLED;
4346 }
4347
4348 /* Ensure that the active index is valid. */
4350
4351 WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, nullptr);
4352
4353 return OPERATOR_FINISHED;
4354}
4355
4357{
4358 /* identifiers */
4359 ot->name = "Remove Tile";
4360 ot->description = "Removes a tile from the image";
4361 ot->idname = "IMAGE_OT_tile_remove";
4362
4363 /* api callbacks */
4366
4367 /* flags */
4369}
4370
4373/* -------------------------------------------------------------------- */
4378{
4379 Image *ima = CTX_data_edit_image(C);
4380
4381 if (ima != nullptr && ima->source == IMA_SRC_TILED) {
4382 /* Filling secondary tiles is only allowed if the primary tile exists. */
4383 return (ima->active_tile_index == 0) || BKE_image_has_ibuf(ima, nullptr);
4384 }
4385 return false;
4386}
4387
4389{
4390 Image *ima = CTX_data_edit_image(C);
4391
4392 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4393 if (!do_fill_tile(op->ptr, ima, tile)) {
4394 return OPERATOR_CANCELLED;
4395 }
4396
4397 WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, nullptr);
4398
4399 return OPERATOR_FINISHED;
4400}
4401
4402static int tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
4403{
4404 tile_fill_init(op->ptr, CTX_data_edit_image(C), nullptr);
4405
4407 C, op, 300, IFACE_("Fill Tile With Generated Image"), IFACE_("Fill"));
4408}
4409
4410static void tile_fill_draw(bContext * /*C*/, wmOperator *op)
4411{
4412 draw_fill_tile(op->ptr, op->layout);
4413}
4414
4416{
4417 /* identifiers */
4418 ot->name = "Fill Tile";
4419 ot->description = "Fill the current tile with a generated image";
4420 ot->idname = "IMAGE_OT_tile_fill";
4421
4422 /* api callbacks */
4426 ot->ui = tile_fill_draw;
4427
4428 /* flags */
4430
4432}
4433
void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
Image * CTX_data_edit_image(const bContext *C)
SpaceImage * CTX_wm_space_image(const bContext *C)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
@ G_FILE_AUTOPACK
void BKE_icon_changed(int icon_id)
Definition icons.cc:205
int BKE_icon_id_ensure(struct ID *id)
Definition icons.cc:268
int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
RenderSlot * BKE_image_get_renderslot(Image *ima, int index)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra)
bool BKE_image_has_filepath(const Image *ima)
void BKE_image_mark_dirty(Image *image, ImBuf *ibuf)
Image * BKE_image_load_exists_in_lib(Main *bmain, std::optional< Library * > owner_library, const char *filepath, bool *r_exists=nullptr)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
bool BKE_image_fill_tile(Image *ima, ImageTile *tile)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
RenderSlot * BKE_image_add_renderslot(Image *ima, const char *name)
void BKE_image_user_file_path(const ImageUser *iuser, const Image *ima, char *filepath)
bool BKE_image_memorypack(Image *ima)
void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
bool BKE_image_is_dirty(Image *image)
#define IMA_UDIM_MAX
Definition BKE_image.hh:38
Image * BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
void BKE_image_sort_tiles(Image *ima)
bool BKE_image_has_anim(Image *image)
void BKE_imageuser_default(ImageUser *iuser)
#define IMA_SIGNAL_SRC_CHANGE
Definition BKE_image.hh:140
bool BKE_image_is_multiview(const Image *ima)
#define IMA_SIGNAL_USER_NEW_IMAGE
Definition BKE_image.hh:142
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
#define IMA_SIGNAL_RELOAD
Definition BKE_image.hh:137
void BKE_image_free_views(Image *image)
bool BKE_image_has_packedfile(const Image *image)
bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int slot)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int slot)
void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
ImageTile * BKE_image_add_tile(Image *ima, int tile_number, const char *label)
bool BKE_image_remove_tile(Image *ima, ImageTile *tile)
bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_image_free_packedfiles(Image *image)
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
Image * BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], bool stereo3d, bool is_data, bool tiled)
bool BKE_image_buffer_format_writable(ImBuf *ibuf)
bool BKE_image_save(ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
bool BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene, Image *ima, ImageUser *iuser, const bool guess_path, const bool save_as_render)
Definition image_save.cc:82
void BKE_image_save_options_update(ImageSaveOptions *opts, const Image *image)
void BKE_image_save_options_free(ImageSaveOptions *opts)
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
void BKE_id_move_to_same_lib(Main &bmain, ID &id, const ID &owner_id)
Definition lib_id.cc:862
void id_us_min(ID *id)
Definition lib_id.cc:359
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
int BKE_packedfile_unpack_image(Main *bmain, ReportList *reports, Image *ima, enum ePF_FileStatus how)
ePF_FileStatus
@ PF_USE_LOCAL
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_reports_free(ReportList *reports)
Definition report.cc:69
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:54
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2877
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition fileops_c.cc:291
struct GSet GSet
Definition BLI_ghash.h:341
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:1004
GSet * BLI_gset_str_new(const char *info)
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.c:959
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE float power_of_2(float f)
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool BLI_path_extension_check_array(const char *path, const char **ext_array) ATTR_NONNULL(1
#define FILE_MAX
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
const char * BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:184
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:180
void BLI_rctf_scale(rctf *rect, float scale)
Definition rct.c:671
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.c:408
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STR_ELEM(...)
Definition BLI_string.h:653
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned char uchar
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define CLAMP(a, b, c)
#define CLAMP_MAX(a, c)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define STREQ(a, b)
#define RPT_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_FRAME_CHANGE
Definition DNA_ID.h:1092
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_EDITORS
Definition DNA_ID.h:1078
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define MAX_ID_NAME
Definition DNA_ID.h:377
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:647
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ ID_IM
@ HISTO_FLAG_SAMPLELINE
@ IMA_GEN_FLOAT
@ IMA_SRC_FILE
@ IMA_SRC_MOVIE
@ IMA_SRC_GENERATED
@ IMA_SRC_VIEWER
@ IMA_SRC_TILED
@ IMA_SRC_SEQUENCE
@ IMA_TYPE_MULTILAYER
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ IMA_USE_VIEWS
@ IMA_GENTYPE_BLANK
Object is a sort of wrapper for general info.
@ R_MULTIVIEW
#define MINAFRAME
@ R_CROP
@ R_BORDER
#define MAXFRAME
@ RGN_TYPE_WINDOW
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_MOVIE
@ FILE_TYPE_FOLDER
@ FILE_TYPE_IMAGE
@ SPACE_IMAGE
@ FILE_DEFAULTDISPLAY
@ SI_MODE_PAINT
@ TEX_IMAGE
#define FRAMENUMBER_MIN_CLAMP(cfra)
@ USER_ZOOM_INVERT
@ USER_ZOOM_TO_MOUSEPOS
@ USER_ZOOM_HORIZ
#define NDOF_PIXELS_PER_SECOND
@ USER_ZOOM_SCALE
@ USER_ZOOM_CONTINUE
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_space_image_release_buffer(SpaceImage *sima, ImBuf *ibuf, void *lock)
void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
ImBuf * ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
bool ED_space_image_check_show_maskedit(SpaceImage *sima, Object *obedit)
void ED_space_image_set(Main *bmain, SpaceImage *sima, Image *ima, bool automatic)
Definition image_edit.cc:46
ListBase ED_image_filesel_detect_sequences(blender::StringRefNull root_path, wmOperator *op, bool detect_udim)
bool ED_space_image_has_buffer(SpaceImage *sima)
bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
bool ED_image_slot_cycle(Image *image, int direction)
void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
bool ED_space_image_cursor_poll(bContext *C)
Image * ED_space_image(const SpaceImage *sima)
Definition image_edit.cc:40
void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
bool ED_space_image_show_cache_and_mval_over(const SpaceImage *sima, ARegion *region, const int mval[2])
bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool handles_as_control_point)
bool ED_maskedit_poll(bContext *C)
Definition mask_edit.cc:30
void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf, ImageUser *iuser)
void ED_image_undo_push_end()
void ED_imapaint_clear_partial_redraw()
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
bool ED_operator_uvedit(bContext *C)
void ED_undo_push_op(bContext *C, wmOperator *op)
Definition ed_undo.cc:381
void unpack_menu(bContext *C, const char *opname, const char *id_name, const char *abs_name, const char *folder, PackedFile *pf)
Definition ed_util.cc:363
void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_imbuf_sample_poll(bContext *C)
int ED_imbuf_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_uvedit_minmax_multi(const Scene *scene, blender::Span< Object * > objects_edit, float r_min[2], float r_max[2])
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
bool IMB_rotate_orthogonal(ImBuf *ibuf, int degrees)
int IMB_anim_get_duration(ImBufAnim *anim, IMB_Timecode_Type tc)
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:779
@ IMB_TC_RECORD_RUN
Contains defines and structs used throughout the imbuf module.
const char * imb_ext_movie[]
@ IMB_COLORMANAGE_IS_DATA
@ IB_rect
@ IB_BITMAPDIRTY
@ IB_MIPMAP_INVALID
@ IB_DISPLAY_BUFFER_INVALID
MovieCacheIter * IMB_moviecacheIter_new(MovieCache *cache)
void IMB_moviecacheIter_free(MovieCacheIter *iter)
bool IMB_moviecacheIter_done(MovieCacheIter *iter)
void IMB_moviecacheIter_step(MovieCacheIter *iter)
ImBuf * IMB_moviecacheIter_getImBuf(MovieCacheIter *iter)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
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 StructOrFunctionRNA
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
@ PROP_PIXEL
Definition RNA_types.hh:151
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:175
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_management)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
@ UI_BUT_LABEL_ALIGN_NONE
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr, bool(*check_prop)(PointerRNA *ptr, PropertyRNA *prop, void *user_data), void *user_data, PropertyRNA *prop_activate_init, eButLabelAlign label_align, bool compact)
#define UI_ITEM_NONE
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
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
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1670
@ WM_FILESEL_FILES
Definition WM_api.hh:937
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:934
@ WM_FILESEL_RELPATH
Definition WM_api.hh:933
@ WM_FILESEL_SHOW_PROPS
Definition WM_api.hh:939
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:936
@ FILE_OPENFILE
Definition WM_api.hh:945
@ FILE_SAVE
Definition WM_api.hh:946
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_LOCK_BYPASS
Definition WM_types.hh:185
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_GRAB_CURSOR_XY
Definition WM_types.hh:168
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DRAW
Definition WM_types.hh:428
#define ND_RENDER_OPTIONS
Definition WM_types.hh:402
@ KM_RELEASE
Definition WM_types.hh:285
#define NC_SCENE
Definition WM_types.hh:345
#define NA_ADDED
Definition WM_types.hh:552
#define ND_SPACE_IMAGE
Definition WM_types.hh:488
#define NA_EDITED
Definition WM_types.hh:550
#define NC_IMAGE
Definition WM_types.hh:351
#define ND_FRAME
Definition WM_types.hh:401
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
@ KM_ALT
Definition WM_types.hh:257
@ KM_SHIFT
Definition WM_types.hh:255
#define NC_SPACE
Definition WM_types.hh:359
volatile int lock
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
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
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
local_group_size(16, 16) .push_constant(Type b
double time
const char * label
#define powf(x, y)
#define ceilf(x)
#define floorf(x)
#define offsetof(t, d)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
bool IMB_saveiff(struct ImBuf *, const char *, int)
void IMB_freeImBuf(ImBuf *)
void IMAGE_OT_view_cursor_center(wmOperatorType *ot)
Definition image_ops.cc:886
static bool tile_remove_poll(bContext *C)
void IMAGE_OT_change_frame(wmOperatorType *ot)
int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports)
static void image_filesel(bContext *C, wmOperator *op, const char *path)
void IMAGE_OT_save_sequence(wmOperatorType *ot)
static bool save_image_op(Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, const ImageSaveOptions *opts)
static bool image_has_valid_path(Image *ima)
static bool image_should_be_saved(Image *ima, bool *r_is_format_writable)
void IMAGE_OT_view_zoom(wmOperatorType *ot)
Definition image_ops.cc:722
void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
static int image_scale_exec(bContext *C, wmOperator *op)
void IMAGE_OT_match_movie_length(wmOperatorType *ot)
static int clear_render_border_exec(bContext *C, wmOperator *)
static void tile_add_draw(bContext *, wmOperator *op)
void IMAGE_OT_save_all_modified(wmOperatorType *ot)
void IMAGE_OT_save_as(wmOperatorType *ot)
static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOperator *op)
static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool image_view_selected_poll(bContext *C)
Definition image_ops.cc:986
void IMAGE_OT_sample(wmOperatorType *ot)
static int image_save_sequence_exec(bContext *C, wmOperator *op)
static bool image_open_draw_check_prop(PointerRNA *, PropertyRNA *prop, void *)
static void sima_zoom_set_factor(SpaceImage *sima, ARegion *region, float zoomfac, const float location[2], const bool zoom_to_pos)
Definition image_ops.cc:131
static void image_new_cancel(bContext *, wmOperator *op)
static int image_view_selected_exec(bContext *C, wmOperator *)
Definition image_ops.cc:940
static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
Definition image_ops.cc:384
static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define IMA_DEF_NAME
static int image_reload_exec(bContext *C, wmOperator *)
bool ED_image_should_save_modified(const Main *bmain)
static void image_save_as_draw(bContext *, wmOperator *op)
static void image_view_zoom_cancel(bContext *C, wmOperator *op)
Definition image_ops.cc:717
static void def_fill_tile(StructOrFunctionRNA *srna)
static Image * image_from_context(const bContext *C)
Definition image_ops.cc:168
void IMAGE_OT_tile_fill(wmOperatorType *ot)
static bool tile_add_poll(bContext *C)
static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
static bool image_clipboard_paste_poll(bContext *C)
static bool image_save_as_check(bContext *C, wmOperator *op)
static bool do_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
static int image_file_browse_exec(bContext *C, wmOperator *op)
static int image_view_zoom_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:572
void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
static int image_sample_line_exec(bContext *C, wmOperator *op)
static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
static int image_open_exec(bContext *C, wmOperator *op)
static bool image_from_context_has_data_poll(bContext *C)
Definition image_ops.cc:220
static bool tile_fill_poll(bContext *C)
void IMAGE_OT_reload(wmOperatorType *ot)
static int image_save_as_exec(bContext *C, wmOperator *op)
void IMAGE_OT_unpack(wmOperatorType *ot)
void IMAGE_OT_view_selected(wmOperatorType *ot)
Definition image_ops.cc:991
void IMAGE_OT_tile_add(wmOperatorType *ot)
void IMAGE_OT_pack(wmOperatorType *ot)
void IMAGE_OT_open(wmOperatorType *ot)
void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
static void image_view_all(SpaceImage *sima, ARegion *region, wmOperator *op)
Definition image_ops.cc:260
static void image_operator_prop_allow_tokens(wmOperatorType *ot)
static bool image_save_as_poll(bContext *C)
static bool image_clipboard_copy_poll(bContext *C)
void IMAGE_OT_invert(wmOperatorType *ot)
static void image_open_cancel(bContext *, wmOperator *op)
void IMAGE_OT_resize(wmOperatorType *ot)
void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
void IMAGE_OT_rotate_orthogonal(wmOperatorType *ot)
static void tile_fill_draw(bContext *, wmOperator *op)
void IMAGE_OT_view_all(wmOperatorType *ot)
Definition image_ops.cc:840
void IMAGE_OT_render_border(wmOperatorType *ot)
void IMAGE_OT_view_pan(wmOperatorType *ot)
Definition image_ops.cc:464
@ GEN_CONTEXT_NONE
@ GEN_CONTEXT_PAINT_CANVAS
@ GEN_CONTEXT_PAINT_STENCIL
static int image_invert_exec(bContext *C, wmOperator *op)
static int frame_from_event(bContext *C, const wmEvent *event)
static int image_remove_render_slot_exec(bContext *C, wmOperator *)
static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout)
static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void IMAGE_OT_clipboard_copy(wmOperatorType *ot)
static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:516
static bool image_not_packed_poll(bContext *C)
Definition image_ops.cc:253
static int image_add_render_slot_exec(bContext *C, wmOperator *)
static void image_save_as_free(wmOperator *op)
static int change_frame_exec(bContext *C, wmOperator *op)
static bool image_file_format_writable(Image *ima, ImageUser *iuser)
static bool image_should_be_saved_when_modified(Image *ima)
void IMAGE_OT_save(wmOperatorType *ot)
static void image_save_as_cancel(bContext *, wmOperator *op)
static int tile_remove_exec(bContext *C, wmOperator *)
static int image_view_all_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:824
static void image_open_draw(bContext *, wmOperator *op)
void IMAGE_OT_file_browse(wmOperatorType *ot)
static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:360
static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int tile_add_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int image_rotate_orthogonal_exec(bContext *C, wmOperator *op)
static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
Definition image_ops.cc:552
static ImageSaveData * image_save_as_init(bContext *C, wmOperator *op)
static int tile_fill_exec(bContext *C, wmOperator *op)
void IMAGE_OT_clipboard_paste(wmOperatorType *ot)
static bool image_cycle_render_slot_poll(bContext *C)
static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:433
static int image_clipboard_paste_exec(bContext *C, wmOperator *op)
static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *user_data)
static int image_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void IMAGE_OT_add_render_slot(wmOperatorType *ot)
void IMAGE_OT_tile_remove(wmOperatorType *ot)
static int render_border_exec(bContext *C, wmOperator *op)
static int image_clipboard_copy_exec(bContext *C, wmOperator *op)
static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void image_open_init(bContext *C, wmOperator *op)
static void tile_fill_init(PointerRNA *ptr, Image *ima, ImageTile *tile)
static int image_view_pan_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:401
static int image_save_exec(bContext *C, wmOperator *op)
static int image_clear_render_slot_exec(bContext *C, wmOperator *)
static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool space_image_main_region_poll(bContext *C)
Definition image_ops.cc:324
bool ED_space_image_get_position(SpaceImage *sima, ARegion *region, const int mval[2], float r_fpos[2])
static int image_read_viewlayers_exec(bContext *C, wmOperator *)
static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:415
static int view_center_cursor_exec(bContext *C, wmOperator *)
Definition image_ops.cc:910
static Image * image_open_single(Main *bmain, Library *owner_library, wmOperator *op, const ImageFrameRange *range, const bool use_multiview)
void IMAGE_OT_flip(wmOperatorType *ot)
static bool image_save_all_modified_poll(bContext *C)
@ VIEW_CONFIRM
Definition image_ops.cc:587
@ VIEW_PASS
Definition image_ops.cc:585
@ VIEW_APPLY
Definition image_ops.cc:586
static bool image_should_pack_during_save_all(const Image *ima)
void IMAGE_OT_sample_line(wmOperatorType *ot)
void IMAGE_OT_replace(wmOperatorType *ot)
static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *region, const rctf *bounds)
Definition image_ops.cc:143
static int image_new_exec(bContext *C, wmOperator *op)
static bool change_frame_poll(bContext *C)
static ImageNewData * image_new_init(bContext *C, wmOperator *op)
static bool image_save_poll(bContext *C)
static void image_view_pan_cancel(bContext *C, wmOperator *op)
Definition image_ops.cc:459
static void sima_zoom_set(SpaceImage *sima, ARegion *region, float zoom, const float location[2], const bool zoom_to_pos)
Definition image_ops.cc:91
static int image_unpack_exec(bContext *C, wmOperator *op)
static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:590
static int image_replace_exec(bContext *C, wmOperator *op)
static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *)
void IMAGE_OT_view_center_cursor(wmOperatorType *ot)
Definition image_ops.cc:922
bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
static int image_save_all_modified_exec(bContext *C, wmOperator *op)
static int tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int image_pack_exec(bContext *C, wmOperator *op)
static void image_new_draw(bContext *, wmOperator *op)
static ImageUser image_user_from_context_and_active_tile(const bContext *C, Image *ima)
Definition image_ops.cc:199
void IMAGE_OT_new(wmOperatorType *ot)
static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:670
static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void change_frame_apply(bContext *C, wmOperator *op)
static int view_cursor_center_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:867
bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
static bool image_file_browse_poll(bContext *C)
static ImageUser * image_user_from_context(const bContext *C)
Definition image_ops.cc:183
static void image_new_free(wmOperator *op)
void IMAGE_OT_clear_render_border(wmOperatorType *ot)
static bool space_image_main_area_not_uv_brush_poll(bContext *C)
Definition image_ops.cc:336
static int image_match_len_exec(bContext *C, wmOperator *)
static int tile_add_exec(bContext *C, wmOperator *op)
static bool image_pack_test(bContext *C, wmOperator *op)
void IMAGE_OT_curves_point_set(wmOperatorType *ot)
static bool image_from_context_editable_has_data_poll_active_tile(bContext *C)
Definition image_ops.cc:239
static int image_flip_exec(bContext *C, wmOperator *op)
static void image_zoom_apply(ViewZoomData *vpd, wmOperator *op, const int x, const int y, const short viewzoom, const short zoom_invert, const bool zoom_to_pos)
Definition image_ops.cc:623
RenderData * RE_engine_get_render_data(Render *re)
#define GS(x)
Definition iris.cc:202
ccl_global const KernelWorkTile * tile
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define G(x, y, z)
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_property_int_set_array(PointerRNA *ptr, PropertyRNA *prop, const int *values)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float_color(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_float(StructOrFunctionRNA *cont_, const char *identifier, 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_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_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
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)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_image_generated_type_items[]
Definition rna_image.cc:34
const EnumPropertyItem rna_enum_unpack_method_items[]
#define min(a, b)
Definition sort.c:32
Render * RE_GetSceneRender(const Scene *scene)
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
#define FLT_MAX
Definition stdcycles.h:14
struct ListBase bg_images
float co[2][2]
Definition DNA_ID.h:413
struct Library * lib
Definition DNA_ID.h:419
char name[66]
Definition DNA_ID.h:425
ColorSpace * colorspace
char filepath[IMB_FILEPATH_SIZE]
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int colormanage_flag
unsigned char planes
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
Stereo3dFormat stereo3d_format
PropertyPointerRNA pprop
ImageUser * iuser
ImageFormatData im_format
PropertyPointerRNA pprop
ImageSaveOptions opts
ImageUser * iuser
ImageFormatData im_format
struct Scene * scene
struct ListBase packedfiles
short last_render_slot
ListBase anims
ListBase renderslots
char views_format
char filepath[1024]
ListBase tiles
short source
short render_slot
struct Stereo3dFormat * stereo3d_format
int active_tile_index
char filepath_abs[1024]
Definition DNA_ID.h:509
char filepath[1024]
Definition DNA_ID.h:531
struct Library_Runtime runtime
Definition DNA_ID.h:535
void * first
ListBase images
Definition BKE_main.hh:218
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
PropertyRNA * prop
Definition RNA_types.hh:49
struct RenderResult * render
int tile_grid_shape[2]
struct Histogram sample_line_hist
struct ImageUser iuser
struct Image * image
struct ImageUser iuser
struct Image * ima
int launch_event
Definition clip_ops.cc:367
bool own_cursor
Definition clip_ops.cc:368
SpaceImage * sima
Definition image_ops.cc:512
float location[2]
Definition clip_ops.cc:541
double timer_lastdraw
Definition clip_ops.cc:543
ARegion * region
Definition image_ops.cc:513
wmTimer * timer
Definition clip_ops.cc:542
bool own_cursor
Definition clip_ops.cc:544
float xmax
float xmin
float ymax
float ymin
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
int mval[2]
Definition WM_types.hh:728
uint8_t modifier
Definition WM_types.hh:739
short type
Definition WM_types.hh:722
void * customdata
Definition WM_types.hh:772
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
bool(* check)(bContext *C, wmOperator *op)
Definition WM_types.hh:1014
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
void(* ui)(bContext *C, wmOperator *op)
Definition WM_types.hh:1053
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
wmWindow * win
Definition WM_types.hh:913
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
void WM_cursor_wait(bool val)
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:51
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
int WM_userdef_event_type_from_keymap_type(int kmitype)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
@ MOUSEPAN
@ RIGHTMOUSE
@ TIMER
@ MOUSEZOOM
@ MOUSEMOVE
@ LEFTMOUSE
@ NDOF_MOTION
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_straightline_cancel(bContext *C, wmOperator *op)
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_border_to_rctf(wmOperator *op, rctf *r_rect)
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
void WM_operator_properties_border(wmOperatorType *ot)
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
void WM_operator_properties_use_cursor_init(wmOperatorType *ot)
void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default)
bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const ImageFormatData *im_format)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
ImBuf * WM_clipboard_image_get()
bool WM_clipboard_image_set(ImBuf *ibuf)
bool WM_clipboard_image_available()
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)