Images: make it harder to accidentally undo image texture painting changes
[blender.git] / source / blender / editors / space_image / image_ops.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spimage
22  */
23
24 #include <stddef.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #ifndef WIN32
30 #  include <unistd.h>
31 #else
32 #  include <io.h>
33 #endif
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_ghash.h"
39 #include "BLI_math.h"
40 #include "BLI_string.h"
41 #include "BLI_utildefines.h"
42
43 #include "BLT_translation.h"
44
45 #include "DNA_camera_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_node_types.h"
48 #include "DNA_packedFile_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51
52 #include "BKE_colortools.h"
53 #include "BKE_context.h"
54 #include "BKE_icons.h"
55 #include "BKE_image.h"
56 #include "BKE_image_save.h"
57 #include "BKE_global.h"
58 #include "BKE_library.h"
59 #include "BKE_main.h"
60 #include "BKE_packedFile.h"
61 #include "BKE_paint.h"
62 #include "BKE_report.h"
63 #include "BKE_screen.h"
64 #include "BKE_sound.h"
65 #include "BKE_scene.h"
66
67 #include "DEG_depsgraph.h"
68
69 #include "GPU_draw.h"
70 #include "GPU_state.h"
71 #include "GPU_immediate.h"
72
73 #include "IMB_colormanagement.h"
74 #include "IMB_imbuf.h"
75 #include "IMB_imbuf_types.h"
76 #include "IMB_moviecache.h"
77 #include "intern/openexr/openexr_multi.h"
78
79 #include "RE_pipeline.h"
80
81 #include "RNA_access.h"
82 #include "RNA_define.h"
83 #include "RNA_enum_types.h"
84
85 #include "ED_image.h"
86 #include "ED_mask.h"
87 #include "ED_paint.h"
88 #include "ED_render.h"
89 #include "ED_screen.h"
90 #include "ED_space_api.h"
91 #include "ED_uvedit.h"
92 #include "ED_util.h"
93
94 #include "UI_interface.h"
95 #include "UI_resources.h"
96 #include "UI_view2d.h"
97
98 #include "WM_api.h"
99 #include "WM_types.h"
100
101 #include "PIL_time.h"
102
103 #include "RE_engine.h"
104
105 #include "image_intern.h"
106
107 /******************** view navigation utilities *********************/
108
109 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom, const float location[2])
110 {
111   float oldzoom = sima->zoom;
112   int width, height;
113
114   sima->zoom = zoom;
115
116   if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
117     /* check zoom limits */
118     ED_space_image_get_size(sima, &width, &height);
119
120     width *= sima->zoom;
121     height *= sima->zoom;
122
123     if ((width < 4) && (height < 4) && sima->zoom < oldzoom) {
124       sima->zoom = oldzoom;
125     }
126     else if (BLI_rcti_size_x(&ar->winrct) <= sima->zoom) {
127       sima->zoom = oldzoom;
128     }
129     else if (BLI_rcti_size_y(&ar->winrct) <= sima->zoom) {
130       sima->zoom = oldzoom;
131     }
132   }
133
134   if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) && location) {
135     float aspx, aspy, w, h;
136
137     ED_space_image_get_size(sima, &width, &height);
138     ED_space_image_get_aspect(sima, &aspx, &aspy);
139
140     w = width * aspx;
141     h = height * aspy;
142
143     sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
144     sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
145   }
146 }
147
148 static void sima_zoom_set_factor(SpaceImage *sima,
149                                  ARegion *ar,
150                                  float zoomfac,
151                                  const float location[2])
152 {
153   sima_zoom_set(sima, ar, sima->zoom * zoomfac, location);
154 }
155
156 /**
157  * Fits the view to the bounds exactly, caller should add margin if needed.
158  */
159 static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *ar, const rctf *bounds)
160 {
161   int image_size[2];
162   float aspx, aspy;
163
164   ED_space_image_get_size(sima, &image_size[0], &image_size[1]);
165   ED_space_image_get_aspect(sima, &aspx, &aspy);
166
167   image_size[0] = image_size[0] * aspx;
168   image_size[1] = image_size[1] * aspy;
169
170   /* adjust offset and zoom */
171   sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]);
172   sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]);
173
174   float size_xy[2], size;
175   size_xy[0] = BLI_rcti_size_x(&ar->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]);
176   size_xy[1] = BLI_rcti_size_y(&ar->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]);
177
178   size = min_ff(size_xy[0], size_xy[1]);
179   CLAMP_MAX(size, 100.0f);
180
181   sima_zoom_set(sima, ar, size, NULL);
182 }
183
184 static Image *image_from_context(const bContext *C)
185 {
186   /* Edit image is set by templates used throughout the interface, so image
187    * operations work outside the image editor. */
188   Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data;
189
190   if (ima) {
191     return ima;
192   }
193   else {
194     /* Image editor. */
195     SpaceImage *sima = CTX_wm_space_image(C);
196     return (sima) ? sima->image : NULL;
197   }
198 }
199
200 static ImageUser *image_user_from_context(const bContext *C)
201 {
202   /* Edit image user is set by templates used throughout the interface, so
203    * image operations work outside the image editor. */
204   ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data;
205
206   if (iuser) {
207     return iuser;
208   }
209   else {
210     /* Image editor. */
211     SpaceImage *sima = CTX_wm_space_image(C);
212     return (sima) ? &sima->iuser : NULL;
213   }
214 }
215
216 static bool image_buffer_exists_from_context(bContext *C)
217 {
218   Image *ima = image_from_context(C);
219   ImageUser *iuser = image_user_from_context(C);
220
221   if (ima == NULL) {
222     return false;
223   }
224
225   void *lock;
226   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
227   const bool has_buffer = (ibuf && (ibuf->rect || ibuf->rect_float));
228   BKE_image_release_ibuf(ima, ibuf, lock);
229   return has_buffer;
230 }
231
232 static bool image_not_packed_poll(bContext *C)
233 {
234   /* Do not run 'replace' on packed images, it does not give user expected results at all. */
235   Image *ima = image_from_context(C);
236   return (ima && BLI_listbase_is_empty(&ima->packedfiles));
237 }
238
239 static bool imbuf_format_writeable(const ImBuf *ibuf)
240 {
241   ImageFormatData im_format;
242   ImbFormatOptions options_dummy;
243   BKE_imbuf_to_image_format(&im_format, ibuf);
244   return (BKE_image_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype);
245 }
246
247 static bool space_image_file_exists_poll(bContext *C)
248 {
249   if (image_buffer_exists_from_context(C) == false) {
250     return false;
251   }
252
253   Main *bmain = CTX_data_main(C);
254   Image *ima = image_from_context(C);
255   ImageUser *iuser = image_user_from_context(C);
256   void *lock;
257   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
258   bool ret = false;
259
260   if (ibuf) {
261     char name[FILE_MAX];
262     BLI_strncpy(name, ibuf->name, FILE_MAX);
263     BLI_path_abs(name, BKE_main_blendfile_path(bmain));
264
265     if (BLI_exists(name) == false) {
266       CTX_wm_operator_poll_msg_set(C, "image file not found");
267     }
268     else if (!BLI_file_is_writable(name)) {
269       CTX_wm_operator_poll_msg_set(C, "image path can't be written to");
270     }
271     else if (!imbuf_format_writeable(ibuf)) {
272       CTX_wm_operator_poll_msg_set(C, "image format is read-only");
273     }
274     else {
275       ret = true;
276     }
277   }
278
279   BKE_image_release_ibuf(ima, ibuf, lock);
280   return ret;
281 }
282
283 bool space_image_main_region_poll(bContext *C)
284 {
285   SpaceImage *sima = CTX_wm_space_image(C);
286   /* XXX ARegion *ar = CTX_wm_region(C); */
287
288   if (sima) {
289     return true; /* XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW); */
290   }
291   return false;
292 }
293
294 /* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode or editmode */
295 static bool space_image_main_area_not_uv_brush_poll(bContext *C)
296 {
297   SpaceImage *sima = CTX_wm_space_image(C);
298   Scene *scene = CTX_data_scene(C);
299   ToolSettings *toolsettings = scene->toolsettings;
300
301   if (sima && !toolsettings->uvsculpt && (CTX_data_edit_object(C) == NULL)) {
302     return 1;
303   }
304
305   return 0;
306 }
307
308 static bool image_sample_poll(bContext *C)
309 {
310   SpaceImage *sima = CTX_wm_space_image(C);
311   if (sima == NULL) {
312     return false;
313   }
314
315   Object *obedit = CTX_data_edit_object(C);
316   if (obedit) {
317     /* Disable when UV editing so it doesn't swallow all click events
318      * (use for setting cursor). */
319     if (ED_space_image_show_uvedit(sima, obedit)) {
320       return false;
321     }
322   }
323   else if (sima->mode != SI_MODE_VIEW) {
324     return false;
325   }
326
327   return true;
328 }
329 /********************** view pan operator *********************/
330
331 typedef struct ViewPanData {
332   float x, y;
333   float xof, yof;
334   int event_type;
335 } ViewPanData;
336
337 static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
338 {
339   SpaceImage *sima = CTX_wm_space_image(C);
340   ViewPanData *vpd;
341
342   op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
343   WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
344
345   vpd->x = event->x;
346   vpd->y = event->y;
347   vpd->xof = sima->xof;
348   vpd->yof = sima->yof;
349   vpd->event_type = event->type;
350
351   WM_event_add_modal_handler(C, op);
352 }
353
354 static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
355 {
356   SpaceImage *sima = CTX_wm_space_image(C);
357   ViewPanData *vpd = op->customdata;
358
359   if (cancel) {
360     sima->xof = vpd->xof;
361     sima->yof = vpd->yof;
362     ED_region_tag_redraw(CTX_wm_region(C));
363   }
364
365   WM_cursor_modal_restore(CTX_wm_window(C));
366   MEM_freeN(op->customdata);
367 }
368
369 static int image_view_pan_exec(bContext *C, wmOperator *op)
370 {
371   SpaceImage *sima = CTX_wm_space_image(C);
372   float offset[2];
373
374   RNA_float_get_array(op->ptr, "offset", offset);
375   sima->xof += offset[0];
376   sima->yof += offset[1];
377
378   ED_region_tag_redraw(CTX_wm_region(C));
379
380   return OPERATOR_FINISHED;
381 }
382
383 static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
384 {
385   if (event->type == MOUSEPAN) {
386     SpaceImage *sima = CTX_wm_space_image(C);
387     float offset[2];
388
389     offset[0] = (event->prevx - event->x) / sima->zoom;
390     offset[1] = (event->prevy - event->y) / sima->zoom;
391     RNA_float_set_array(op->ptr, "offset", offset);
392
393     image_view_pan_exec(C, op);
394     return OPERATOR_FINISHED;
395   }
396   else {
397     image_view_pan_init(C, op, event);
398     return OPERATOR_RUNNING_MODAL;
399   }
400 }
401
402 static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
403 {
404   SpaceImage *sima = CTX_wm_space_image(C);
405   ViewPanData *vpd = op->customdata;
406   float offset[2];
407
408   switch (event->type) {
409     case MOUSEMOVE:
410       sima->xof = vpd->xof;
411       sima->yof = vpd->yof;
412       offset[0] = (vpd->x - event->x) / sima->zoom;
413       offset[1] = (vpd->y - event->y) / sima->zoom;
414       RNA_float_set_array(op->ptr, "offset", offset);
415       image_view_pan_exec(C, op);
416       break;
417     default:
418       if (event->type == vpd->event_type && event->val == KM_RELEASE) {
419         image_view_pan_exit(C, op, false);
420         return OPERATOR_FINISHED;
421       }
422       break;
423   }
424
425   return OPERATOR_RUNNING_MODAL;
426 }
427
428 static void image_view_pan_cancel(bContext *C, wmOperator *op)
429 {
430   image_view_pan_exit(C, op, true);
431 }
432
433 void IMAGE_OT_view_pan(wmOperatorType *ot)
434 {
435   /* identifiers */
436   ot->name = "Pan View";
437   ot->idname = "IMAGE_OT_view_pan";
438   ot->description = "Pan the view";
439
440   /* api callbacks */
441   ot->exec = image_view_pan_exec;
442   ot->invoke = image_view_pan_invoke;
443   ot->modal = image_view_pan_modal;
444   ot->cancel = image_view_pan_cancel;
445   ot->poll = space_image_main_region_poll;
446
447   /* flags */
448   ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
449
450   /* properties */
451   RNA_def_float_vector(ot->srna,
452                        "offset",
453                        2,
454                        NULL,
455                        -FLT_MAX,
456                        FLT_MAX,
457                        "Offset",
458                        "Offset in floating point units, 1.0 is the width and height of the image",
459                        -FLT_MAX,
460                        FLT_MAX);
461 }
462
463 /********************** view zoom operator *********************/
464
465 typedef struct ViewZoomData {
466   float origx, origy;
467   float zoom;
468   int event_type;
469   float location[2];
470
471   /* needed for continuous zoom */
472   wmTimer *timer;
473   double timer_lastdraw;
474
475   /* */
476   SpaceImage *sima;
477   ARegion *ar;
478 } ViewZoomData;
479
480 static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
481 {
482   SpaceImage *sima = CTX_wm_space_image(C);
483   ARegion *ar = CTX_wm_region(C);
484   ViewZoomData *vpd;
485
486   op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
487   WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
488
489   vpd->origx = event->x;
490   vpd->origy = event->y;
491   vpd->zoom = sima->zoom;
492   vpd->event_type = event->type;
493
494   UI_view2d_region_to_view(
495       &ar->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
496
497   if (U.viewzoom == USER_ZOOM_CONT) {
498     /* needs a timer to continue redrawing */
499     vpd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
500     vpd->timer_lastdraw = PIL_check_seconds_timer();
501   }
502
503   vpd->sima = sima;
504   vpd->ar = ar;
505
506   WM_event_add_modal_handler(C, op);
507 }
508
509 static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
510 {
511   SpaceImage *sima = CTX_wm_space_image(C);
512   ViewZoomData *vpd = op->customdata;
513
514   if (cancel) {
515     sima->zoom = vpd->zoom;
516     ED_region_tag_redraw(CTX_wm_region(C));
517   }
518
519   if (vpd->timer) {
520     WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
521   }
522
523   WM_cursor_modal_restore(CTX_wm_window(C));
524   MEM_freeN(op->customdata);
525 }
526
527 static int image_view_zoom_exec(bContext *C, wmOperator *op)
528 {
529   SpaceImage *sima = CTX_wm_space_image(C);
530   ARegion *ar = CTX_wm_region(C);
531
532   sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"), NULL);
533
534   ED_region_tag_redraw(ar);
535
536   return OPERATOR_FINISHED;
537 }
538
539 enum {
540   VIEW_PASS = 0,
541   VIEW_APPLY,
542   VIEW_CONFIRM,
543 };
544
545 static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
546 {
547   if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
548     SpaceImage *sima = CTX_wm_space_image(C);
549     ARegion *ar = CTX_wm_region(C);
550     float delta, factor, location[2];
551
552     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
553
554     delta = event->prevx - event->x + event->prevy - event->y;
555
556     if (U.uiflag & USER_ZOOM_INVERT) {
557       delta *= -1;
558     }
559
560     factor = 1.0f + delta / 300.0f;
561     RNA_float_set(op->ptr, "factor", factor);
562     sima_zoom_set(sima, ar, sima->zoom * factor, location);
563     ED_region_tag_redraw(ar);
564
565     return OPERATOR_FINISHED;
566   }
567   else {
568     image_view_zoom_init(C, op, event);
569     return OPERATOR_RUNNING_MODAL;
570   }
571 }
572
573 static void image_zoom_apply(ViewZoomData *vpd,
574                              wmOperator *op,
575                              const int x,
576                              const int y,
577                              const short viewzoom,
578                              const short zoom_invert)
579 {
580   float factor;
581
582   if (viewzoom == USER_ZOOM_CONT) {
583     double time = PIL_check_seconds_timer();
584     float time_step = (float)(time - vpd->timer_lastdraw);
585     float fac;
586     float zfac;
587
588     if (U.uiflag & USER_ZOOM_HORIZ) {
589       fac = (float)(x - vpd->origx);
590     }
591     else {
592       fac = (float)(y - vpd->origy);
593     }
594
595     if (zoom_invert) {
596       fac = -fac;
597     }
598
599     /* oldstyle zoom */
600     zfac = 1.0f + ((fac / 20.0f) * time_step);
601     vpd->timer_lastdraw = time;
602     /* this is the final zoom, but instead make it into a factor */
603     // zoom = vpd->sima->zoom * zfac;
604     factor = (vpd->sima->zoom * zfac) / vpd->zoom;
605   }
606   else {
607     /* for now do the same things for scale and dolly */
608     float delta = x - vpd->origx + y - vpd->origy;
609
610     if (zoom_invert) {
611       delta *= -1.0f;
612     }
613
614     factor = 1.0f + delta / 300.0f;
615   }
616
617   RNA_float_set(op->ptr, "factor", factor);
618   sima_zoom_set(vpd->sima, vpd->ar, vpd->zoom * factor, vpd->location);
619   ED_region_tag_redraw(vpd->ar);
620 }
621
622 static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
623 {
624   ViewZoomData *vpd = op->customdata;
625   short event_code = VIEW_PASS;
626
627   /* execute the events */
628   if (event->type == TIMER && event->customdata == vpd->timer) {
629     /* continuous zoom */
630     event_code = VIEW_APPLY;
631   }
632   else if (event->type == MOUSEMOVE) {
633     event_code = VIEW_APPLY;
634   }
635   else if (event->type == vpd->event_type && event->val == KM_RELEASE) {
636     event_code = VIEW_CONFIRM;
637   }
638
639   if (event_code == VIEW_APPLY) {
640     image_zoom_apply(vpd, op, event->x, event->y, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
641   }
642   else if (event_code == VIEW_CONFIRM) {
643     image_view_zoom_exit(C, op, false);
644     return OPERATOR_FINISHED;
645   }
646
647   return OPERATOR_RUNNING_MODAL;
648 }
649
650 static void image_view_zoom_cancel(bContext *C, wmOperator *op)
651 {
652   image_view_zoom_exit(C, op, true);
653 }
654
655 void IMAGE_OT_view_zoom(wmOperatorType *ot)
656 {
657   PropertyRNA *prop;
658
659   /* identifiers */
660   ot->name = "Zoom View";
661   ot->idname = "IMAGE_OT_view_zoom";
662   ot->description = "Zoom in/out the image";
663
664   /* api callbacks */
665   ot->exec = image_view_zoom_exec;
666   ot->invoke = image_view_zoom_invoke;
667   ot->modal = image_view_zoom_modal;
668   ot->cancel = image_view_zoom_cancel;
669   ot->poll = space_image_main_region_poll;
670
671   /* flags */
672   ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
673
674   /* properties */
675   prop = RNA_def_float(ot->srna,
676                        "factor",
677                        0.0f,
678                        -FLT_MAX,
679                        FLT_MAX,
680                        "Factor",
681                        "Zoom factor, values higher than 1.0 zoom in, lower values zoom out",
682                        -FLT_MAX,
683                        FLT_MAX);
684   RNA_def_property_flag(prop, PROP_HIDDEN);
685 }
686
687 #ifdef WITH_INPUT_NDOF
688 /********************** NDOF operator *********************/
689
690 /* Combined pan/zoom from a 3D mouse device.
691  * Z zooms, XY pans
692  * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
693  * that explains the negative signs in the code below
694  */
695
696 static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
697 {
698   if (event->type != NDOF_MOTION) {
699     return OPERATOR_CANCELLED;
700   }
701   else {
702     SpaceImage *sima = CTX_wm_space_image(C);
703     ARegion *ar = CTX_wm_region(C);
704     float pan_vec[3];
705
706     const wmNDOFMotionData *ndof = event->customdata;
707     const float speed = NDOF_PIXELS_PER_SECOND;
708
709     WM_event_ndof_pan_get(ndof, pan_vec, true);
710
711     mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom);
712     pan_vec[2] *= -ndof->dt;
713
714     sima_zoom_set_factor(sima, ar, 1.0f + pan_vec[2], NULL);
715     sima->xof += pan_vec[0];
716     sima->yof += pan_vec[1];
717
718     ED_region_tag_redraw(ar);
719
720     return OPERATOR_FINISHED;
721   }
722 }
723
724 void IMAGE_OT_view_ndof(wmOperatorType *ot)
725 {
726   /* identifiers */
727   ot->name = "NDOF Pan/Zoom";
728   ot->idname = "IMAGE_OT_view_ndof";
729   ot->description = "Use a 3D mouse device to pan/zoom the view";
730
731   /* api callbacks */
732   ot->invoke = image_view_ndof_invoke;
733   ot->poll = space_image_main_region_poll;
734
735   /* flags */
736   ot->flag = OPTYPE_LOCK_BYPASS;
737 }
738 #endif /* WITH_INPUT_NDOF */
739
740 /********************** view all operator *********************/
741
742 /* Updates the fields of the View2D member of the SpaceImage struct.
743  * Default behavior is to reset the position of the image and set the zoom to 1
744  * If the image will not fit within the window rectangle, the zoom is adjusted */
745
746 static int image_view_all_exec(bContext *C, wmOperator *op)
747 {
748   SpaceImage *sima;
749   ARegion *ar;
750   float aspx, aspy, zoomx, zoomy, w, h;
751   int width, height;
752   const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
753
754   /* retrieve state */
755   sima = CTX_wm_space_image(C);
756   ar = CTX_wm_region(C);
757
758   ED_space_image_get_size(sima, &width, &height);
759   ED_space_image_get_aspect(sima, &aspx, &aspy);
760
761   w = width * aspx;
762   h = height * aspy;
763
764   /* check if the image will fit in the image with (zoom == 1) */
765   width = BLI_rcti_size_x(&ar->winrct) + 1;
766   height = BLI_rcti_size_y(&ar->winrct) + 1;
767
768   if (fit_view) {
769     const int margin = 5; /* margin from border */
770
771     zoomx = (float)width / (w + 2 * margin);
772     zoomy = (float)height / (h + 2 * margin);
773
774     sima_zoom_set(sima, ar, min_ff(zoomx, zoomy), NULL);
775   }
776   else {
777     if ((w >= width || h >= height) && (width > 0 && height > 0)) {
778       zoomx = (float)width / w;
779       zoomy = (float)height / h;
780
781       /* find the zoom value that will fit the image in the image space */
782       sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL);
783     }
784     else {
785       sima_zoom_set(sima, ar, 1.0f, NULL);
786     }
787   }
788
789   sima->xof = sima->yof = 0.0f;
790
791   ED_region_tag_redraw(ar);
792
793   return OPERATOR_FINISHED;
794 }
795
796 void IMAGE_OT_view_all(wmOperatorType *ot)
797 {
798   PropertyRNA *prop;
799
800   /* identifiers */
801   ot->name = "View All";
802   ot->idname = "IMAGE_OT_view_all";
803   ot->description = "View the entire image";
804
805   /* api callbacks */
806   ot->exec = image_view_all_exec;
807   ot->poll = space_image_main_region_poll;
808
809   /* flags */
810   ot->flag = OPTYPE_LOCK_BYPASS;
811
812   /* properties */
813   prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
814   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
815 }
816
817 /********************** view selected operator *********************/
818
819 static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
820 {
821   SpaceImage *sima;
822   ARegion *ar;
823   Scene *scene;
824   ViewLayer *view_layer;
825   Object *obedit;
826   Image *ima;
827
828   /* retrieve state */
829   sima = CTX_wm_space_image(C);
830   ar = CTX_wm_region(C);
831   scene = CTX_data_scene(C);
832   view_layer = CTX_data_view_layer(C);
833   obedit = CTX_data_edit_object(C);
834
835   ima = ED_space_image(sima);
836
837   /* get bounds */
838   float min[2], max[2];
839   if (ED_space_image_show_uvedit(sima, obedit)) {
840     if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) {
841       return OPERATOR_CANCELLED;
842     }
843   }
844   else if (ED_space_image_check_show_maskedit(sima, view_layer)) {
845     if (!ED_mask_selected_minmax(C, min, max)) {
846       return OPERATOR_CANCELLED;
847     }
848   }
849   rctf bounds = {
850       .xmin = min[0],
851       .ymin = min[1],
852       .xmax = max[0],
853       .ymax = max[1],
854   };
855
856   /* add some margin */
857   BLI_rctf_scale(&bounds, 1.4f);
858
859   sima_zoom_set_from_bounds(sima, ar, &bounds);
860
861   ED_region_tag_redraw(ar);
862
863   return OPERATOR_FINISHED;
864 }
865
866 static bool image_view_selected_poll(bContext *C)
867 {
868   return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
869 }
870
871 void IMAGE_OT_view_selected(wmOperatorType *ot)
872 {
873   /* identifiers */
874   ot->name = "View Center";
875   ot->idname = "IMAGE_OT_view_selected";
876   ot->description = "View all selected UVs";
877
878   /* api callbacks */
879   ot->exec = image_view_selected_exec;
880   ot->poll = image_view_selected_poll;
881 }
882
883 /********************** view zoom in/out operator *********************/
884
885 static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
886 {
887   SpaceImage *sima = CTX_wm_space_image(C);
888   ARegion *ar = CTX_wm_region(C);
889   float location[2];
890
891   RNA_float_get_array(op->ptr, "location", location);
892
893   sima_zoom_set_factor(sima, ar, powf(2.0f, 1.0f / 3.0f), location);
894
895   ED_region_tag_redraw(ar);
896
897   return OPERATOR_FINISHED;
898 }
899
900 static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
901 {
902   ARegion *ar = CTX_wm_region(C);
903   float location[2];
904
905   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
906   RNA_float_set_array(op->ptr, "location", location);
907
908   return image_view_zoom_in_exec(C, op);
909 }
910
911 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
912 {
913   PropertyRNA *prop;
914
915   /* identifiers */
916   ot->name = "View Zoom In";
917   ot->idname = "IMAGE_OT_view_zoom_in";
918   ot->description = "Zoom in the image (centered around 2D cursor)";
919
920   /* api callbacks */
921   ot->invoke = image_view_zoom_in_invoke;
922   ot->exec = image_view_zoom_in_exec;
923   ot->poll = space_image_main_region_poll;
924
925   /* flags */
926   ot->flag = OPTYPE_LOCK_BYPASS;
927
928   /* properties */
929   prop = RNA_def_float_vector(ot->srna,
930                               "location",
931                               2,
932                               NULL,
933                               -FLT_MAX,
934                               FLT_MAX,
935                               "Location",
936                               "Cursor location in screen coordinates",
937                               -10.0f,
938                               10.0f);
939   RNA_def_property_flag(prop, PROP_HIDDEN);
940 }
941
942 static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
943 {
944   SpaceImage *sima = CTX_wm_space_image(C);
945   ARegion *ar = CTX_wm_region(C);
946   float location[2];
947
948   RNA_float_get_array(op->ptr, "location", location);
949
950   sima_zoom_set_factor(sima, ar, powf(0.5f, 1.0f / 3.0f), location);
951
952   ED_region_tag_redraw(ar);
953
954   return OPERATOR_FINISHED;
955 }
956
957 static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
958 {
959   ARegion *ar = CTX_wm_region(C);
960   float location[2];
961
962   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
963   RNA_float_set_array(op->ptr, "location", location);
964
965   return image_view_zoom_out_exec(C, op);
966 }
967
968 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
969 {
970   PropertyRNA *prop;
971
972   /* identifiers */
973   ot->name = "View Zoom Out";
974   ot->idname = "IMAGE_OT_view_zoom_out";
975   ot->description = "Zoom out the image (centered around 2D cursor)";
976
977   /* api callbacks */
978   ot->invoke = image_view_zoom_out_invoke;
979   ot->exec = image_view_zoom_out_exec;
980   ot->poll = space_image_main_region_poll;
981
982   /* flags */
983   ot->flag = OPTYPE_LOCK_BYPASS;
984
985   /* properties */
986   prop = RNA_def_float_vector(ot->srna,
987                               "location",
988                               2,
989                               NULL,
990                               -FLT_MAX,
991                               FLT_MAX,
992                               "Location",
993                               "Cursor location in screen coordinates",
994                               -10.0f,
995                               10.0f);
996   RNA_def_property_flag(prop, PROP_HIDDEN);
997 }
998
999 /********************** view zoom ratio operator *********************/
1000
1001 static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
1002 {
1003   SpaceImage *sima = CTX_wm_space_image(C);
1004   ARegion *ar = CTX_wm_region(C);
1005
1006   sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"), NULL);
1007
1008   /* ensure pixel exact locations for draw */
1009   sima->xof = (int)sima->xof;
1010   sima->yof = (int)sima->yof;
1011
1012   ED_region_tag_redraw(ar);
1013
1014   return OPERATOR_FINISHED;
1015 }
1016
1017 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
1018 {
1019   /* identifiers */
1020   ot->name = "View Zoom Ratio";
1021   ot->idname = "IMAGE_OT_view_zoom_ratio";
1022   ot->description = "Set zoom ratio of the view";
1023
1024   /* api callbacks */
1025   ot->exec = image_view_zoom_ratio_exec;
1026   ot->poll = space_image_main_region_poll;
1027
1028   /* flags */
1029   ot->flag = OPTYPE_LOCK_BYPASS;
1030
1031   /* properties */
1032   RNA_def_float(ot->srna,
1033                 "ratio",
1034                 0.0f,
1035                 -FLT_MAX,
1036                 FLT_MAX,
1037                 "Ratio",
1038                 "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out",
1039                 -FLT_MAX,
1040                 FLT_MAX);
1041 }
1042
1043 /********************** view border-zoom operator *********************/
1044
1045 static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
1046 {
1047   SpaceImage *sima = CTX_wm_space_image(C);
1048   ARegion *ar = CTX_wm_region(C);
1049   rctf bounds;
1050   const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
1051
1052   WM_operator_properties_border_to_rctf(op, &bounds);
1053
1054   UI_view2d_region_to_view_rctf(&ar->v2d, &bounds, &bounds);
1055
1056   const struct {
1057     float xof;
1058     float yof;
1059     float zoom;
1060   } sima_view_prev = {
1061       .xof = sima->xof,
1062       .yof = sima->yof,
1063       .zoom = sima->zoom,
1064   };
1065
1066   sima_zoom_set_from_bounds(sima, ar, &bounds);
1067
1068   /* zoom out */
1069   if (!zoom_in) {
1070     sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof);
1071     sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof);
1072     sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom);
1073   }
1074
1075   ED_region_tag_redraw(ar);
1076
1077   return OPERATOR_FINISHED;
1078 }
1079
1080 void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
1081 {
1082   /* identifiers */
1083   ot->name = "Zoom to Border";
1084   ot->description = "Zoom in the view to the nearest item contained in the border";
1085   ot->idname = "IMAGE_OT_view_zoom_border";
1086
1087   /* api callbacks */
1088   ot->invoke = WM_gesture_box_invoke;
1089   ot->exec = image_view_zoom_border_exec;
1090   ot->modal = WM_gesture_box_modal;
1091   ot->cancel = WM_gesture_box_cancel;
1092
1093   ot->poll = space_image_main_region_poll;
1094
1095   /* rna */
1096   WM_operator_properties_gesture_box_zoom(ot);
1097 }
1098
1099 /**************** load/replace/save callbacks ******************/
1100 static void image_filesel(bContext *C, wmOperator *op, const char *path)
1101 {
1102   RNA_string_set(op->ptr, "filepath", path);
1103   WM_event_add_fileselect(C, op);
1104 }
1105
1106 /******************** open image operator ********************/
1107
1108 typedef struct ImageOpenData {
1109   PropertyPointerRNA pprop;
1110   ImageUser *iuser;
1111   ImageFormatData im_format;
1112 } ImageOpenData;
1113
1114 typedef struct ImageFrameRange {
1115   struct ImageFrameRange *next, *prev;
1116   ListBase frames;
1117   /**  The full path of the first file in the list of image files */
1118   char filepath[FILE_MAX];
1119 } ImageFrameRange;
1120
1121 typedef struct ImageFrame {
1122   struct ImageFrame *next, *prev;
1123   int framenr;
1124 } ImageFrame;
1125
1126 static void image_open_init(bContext *C, wmOperator *op)
1127 {
1128   ImageOpenData *iod;
1129   op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
1130   iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
1131   UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
1132 }
1133
1134 static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
1135 {
1136   MEM_freeN(op->customdata);
1137   op->customdata = NULL;
1138 }
1139
1140 /**
1141  * Get a list of frames from the list of image files matching the first file name sequence pattern.
1142  * \param ptr[in]: The RNA pointer containing the "directory" entry and "files" collection.
1143  * \param frames_all[out]: the list of frame numbers found in the files matching
1144  * the first one by name.
1145  */
1146 static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
1147 {
1148   char dir[FILE_MAXDIR];
1149   const bool do_frame_range = RNA_boolean_get(ptr, "use_sequence_detection");
1150   ImageFrameRange *frame_range = NULL;
1151
1152   RNA_string_get(ptr, "directory", dir);
1153   RNA_BEGIN (ptr, itemptr, "files") {
1154     char base_head[FILE_MAX], base_tail[FILE_MAX];
1155     char head[FILE_MAX], tail[FILE_MAX];
1156     unsigned short digits;
1157     char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
1158     ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
1159
1160     /* use the first file in the list as base filename */
1161     frame->framenr = BLI_stringdec(filename, head, tail, &digits);
1162
1163     /* still in the same sequence */
1164     if (do_frame_range && (frame_range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) &&
1165         (STREQLEN(base_tail, tail, FILE_MAX))) {
1166       /* pass */
1167     }
1168     else {
1169       /* start a new frame range */
1170       frame_range = MEM_callocN(sizeof(*frame_range), __func__);
1171       BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename);
1172       BLI_addtail(frames_all, frame_range);
1173
1174       BLI_strncpy(base_head, head, sizeof(base_head));
1175       BLI_strncpy(base_tail, tail, sizeof(base_tail));
1176     }
1177
1178     BLI_addtail(&frame_range->frames, frame);
1179     MEM_freeN(filename);
1180   }
1181   RNA_END;
1182 }
1183
1184 static int image_cmp_frame(const void *a, const void *b)
1185 {
1186   const ImageFrame *frame_a = a;
1187   const ImageFrame *frame_b = b;
1188
1189   if (frame_a->framenr < frame_b->framenr) {
1190     return -1;
1191   }
1192   if (frame_a->framenr > frame_b->framenr) {
1193     return 1;
1194   }
1195   return 0;
1196 }
1197
1198 /**
1199  * Return the start (offset) and the length of the sequence of
1200  * continuous frames in the list of frames.
1201  *
1202  * \param frames: [in] the list of frame numbers, as a side-effect the list is sorted.
1203  * \param ofs: [out] offset the first frame number in the sequence.
1204  * \return the number of contiguous frames in the sequence
1205  */
1206 static int image_sequence_get_len(ListBase *frames, int *ofs)
1207 {
1208   ImageFrame *frame;
1209
1210   BLI_listbase_sort(frames, image_cmp_frame);
1211
1212   frame = frames->first;
1213   if (frame) {
1214     int frame_curr = frame->framenr;
1215     (*ofs) = frame_curr;
1216     while (frame && (frame->framenr == frame_curr)) {
1217       frame_curr++;
1218       frame = frame->next;
1219     }
1220     return frame_curr - (*ofs);
1221   }
1222   *ofs = 0;
1223   return 0;
1224 }
1225
1226 static Image *image_open_single(Main *bmain,
1227                                 wmOperator *op,
1228                                 const char *filepath,
1229                                 const char *relbase,
1230                                 bool is_relative_path,
1231                                 bool use_multiview,
1232                                 int frame_seq_len)
1233 {
1234   bool exists = false;
1235   Image *ima = NULL;
1236
1237   errno = 0;
1238   ima = BKE_image_load_exists_ex(bmain, filepath, &exists);
1239
1240   if (!ima) {
1241     if (op->customdata) {
1242       MEM_freeN(op->customdata);
1243     }
1244     BKE_reportf(op->reports,
1245                 RPT_ERROR,
1246                 "Cannot read '%s': %s",
1247                 filepath,
1248                 errno ? strerror(errno) : TIP_("unsupported image format"));
1249     return NULL;
1250   }
1251
1252   if (!exists) {
1253     /* only image path after save, never ibuf */
1254     if (is_relative_path) {
1255       BLI_path_rel(ima->name, relbase);
1256     }
1257
1258     /* handle multiview images */
1259     if (use_multiview) {
1260       ImageOpenData *iod = op->customdata;
1261       ImageFormatData *imf = &iod->im_format;
1262
1263       ima->flag |= IMA_USE_VIEWS;
1264       ima->views_format = imf->views_format;
1265       *ima->stereo3d_format = imf->stereo3d_format;
1266     }
1267     else {
1268       ima->flag &= ~IMA_USE_VIEWS;
1269       BKE_image_free_views(ima);
1270     }
1271
1272     if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
1273       ima->source = IMA_SRC_SEQUENCE;
1274     }
1275   }
1276
1277   return ima;
1278 }
1279
1280 static int image_open_exec(bContext *C, wmOperator *op)
1281 {
1282   Main *bmain = CTX_data_main(C);
1283   ScrArea *sa = CTX_wm_area(C);
1284   Scene *scene = CTX_data_scene(C);
1285   Object *obedit = CTX_data_edit_object(C);
1286   ImageUser *iuser = NULL;
1287   ImageOpenData *iod = op->customdata;
1288   Image *ima = NULL;
1289   char filepath[FILE_MAX];
1290   int frame_seq_len = 0;
1291   int frame_ofs = 1;
1292
1293   const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
1294   const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
1295
1296   if (!op->customdata) {
1297     image_open_init(C, op);
1298   }
1299
1300   RNA_string_get(op->ptr, "filepath", filepath);
1301
1302   if (RNA_struct_property_is_set(op->ptr, "directory") &&
1303       RNA_struct_property_is_set(op->ptr, "files")) {
1304     bool was_relative = BLI_path_is_rel(filepath);
1305     ListBase frame_ranges_all;
1306
1307     BLI_listbase_clear(&frame_ranges_all);
1308     image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
1309     for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range;
1310          frame_range = frame_range->next) {
1311       int frame_range_ofs;
1312       int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
1313       BLI_freelistN(&frame_range->frames);
1314
1315       char filepath_range[FILE_MAX];
1316       BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
1317
1318       if (was_relative) {
1319         BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
1320       }
1321
1322       Image *ima_range = image_open_single(bmain,
1323                                            op,
1324                                            filepath_range,
1325                                            BKE_main_blendfile_path(bmain),
1326                                            is_relative_path,
1327                                            use_multiview,
1328                                            frame_range_seq_len);
1329
1330       /* take the first image */
1331       if ((ima == NULL) && ima_range) {
1332         ima = ima_range;
1333         frame_seq_len = frame_range_seq_len;
1334         frame_ofs = frame_range_ofs;
1335       }
1336     }
1337     BLI_freelistN(&frame_ranges_all);
1338   }
1339   else {
1340     /* for drag & drop etc. */
1341     ima = image_open_single(
1342         bmain, op, filepath, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview, 1);
1343   }
1344
1345   if (ima == NULL) {
1346     return OPERATOR_CANCELLED;
1347   }
1348
1349   /* hook into UI */
1350   iod = op->customdata;
1351
1352   if (iod->pprop.prop) {
1353     /* when creating new ID blocks, use is already 1, but RNA
1354      * pointer use also increases user, so this compensates it */
1355     id_us_min(&ima->id);
1356
1357     PointerRNA imaptr;
1358     RNA_id_pointer_create(&ima->id, &imaptr);
1359     RNA_property_pointer_set(NULL, &iod->pprop.ptr, iod->pprop.prop, imaptr);
1360     RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1361   }
1362
1363   if (iod->iuser) {
1364     iuser = iod->iuser;
1365   }
1366   else if (sa && sa->spacetype == SPACE_IMAGE) {
1367     SpaceImage *sima = sa->spacedata.first;
1368     ED_space_image_set(bmain, sima, obedit, ima, false);
1369     iuser = &sima->iuser;
1370   }
1371   else {
1372     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1373     if (tex && tex->type == TEX_IMAGE) {
1374       iuser = &tex->iuser;
1375     }
1376
1377     if (iuser == NULL) {
1378       Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
1379       if (cam) {
1380         for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
1381           if (bgpic->ima == ima) {
1382             iuser = &bgpic->iuser;
1383             break;
1384           }
1385         }
1386       }
1387     }
1388   }
1389
1390   /* initialize because of new image */
1391   if (iuser) {
1392     iuser->frames = frame_seq_len;
1393     iuser->sfra = 1;
1394     iuser->framenr = 1;
1395     if (ima->source == IMA_SRC_MOVIE) {
1396       iuser->offset = 0;
1397     }
1398     else {
1399       iuser->offset = frame_ofs - 1;
1400     }
1401     iuser->scene = scene;
1402     BKE_image_init_imageuser(ima, iuser);
1403   }
1404
1405   /* XXX unpackImage frees image buffers */
1406   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1407
1408   BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
1409   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1410
1411   MEM_freeN(op->customdata);
1412
1413   return OPERATOR_FINISHED;
1414 }
1415
1416 static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1417 {
1418   SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1419   const char *path = U.textudir;
1420   Image *ima = NULL;
1421   Scene *scene = CTX_data_scene(C);
1422
1423   if (sima) {
1424     ima = sima->image;
1425   }
1426
1427   if (ima == NULL) {
1428     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1429     if (tex && tex->type == TEX_IMAGE) {
1430       ima = tex->ima;
1431     }
1432   }
1433
1434   if (ima == NULL) {
1435     PointerRNA ptr;
1436     PropertyRNA *prop;
1437
1438     /* hook into UI */
1439     UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
1440
1441     if (prop) {
1442       PointerRNA oldptr;
1443       Image *oldima;
1444
1445       oldptr = RNA_property_pointer_get(&ptr, prop);
1446       oldima = (Image *)oldptr.id.data;
1447       /* unlikely to fail but better avoid strange crash */
1448       if (oldima && GS(oldima->id.name) == ID_IM) {
1449         ima = oldima;
1450       }
1451     }
1452   }
1453
1454   if (ima) {
1455     path = ima->name;
1456   }
1457
1458   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1459     return image_open_exec(C, op);
1460   }
1461
1462   image_open_init(C, op);
1463
1464   /* show multiview save options only if scene has multiviews */
1465   PropertyRNA *prop;
1466   prop = RNA_struct_find_property(op->ptr, "show_multiview");
1467   RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1468
1469   image_filesel(C, op, path);
1470
1471   return OPERATOR_RUNNING_MODAL;
1472 }
1473
1474 static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr),
1475                                        PropertyRNA *prop,
1476                                        void *UNUSED(user_data))
1477 {
1478   const char *prop_id = RNA_property_identifier(prop);
1479
1480   return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
1481            STREQ(prop_id, "filename"));
1482 }
1483
1484 static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
1485 {
1486   uiLayout *layout = op->layout;
1487   ImageOpenData *iod = op->customdata;
1488   ImageFormatData *imf = &iod->im_format;
1489   PointerRNA imf_ptr, ptr;
1490
1491   /* main draw call */
1492   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1493   uiDefAutoButsRNA(
1494       layout, &ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
1495
1496   /* image template */
1497   RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1498
1499   /* multiview template */
1500   if (RNA_boolean_get(op->ptr, "show_multiview")) {
1501     uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1502   }
1503 }
1504
1505 /* called by other space types too */
1506 void IMAGE_OT_open(wmOperatorType *ot)
1507 {
1508   /* identifiers */
1509   ot->name = "Open Image";
1510   ot->description = "Open image";
1511   ot->idname = "IMAGE_OT_open";
1512
1513   /* api callbacks */
1514   ot->exec = image_open_exec;
1515   ot->invoke = image_open_invoke;
1516   ot->cancel = image_open_cancel;
1517   ot->ui = image_open_draw;
1518
1519   /* flags */
1520   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1521
1522   /* properties */
1523   WM_operator_properties_filesel(ot,
1524                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
1525                                  FILE_SPECIAL,
1526                                  FILE_OPENFILE,
1527                                  WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES |
1528                                      WM_FILESEL_RELPATH,
1529                                  FILE_DEFAULTDISPLAY,
1530                                  FILE_SORT_ALPHA);
1531
1532   RNA_def_boolean(
1533       ot->srna,
1534       "use_sequence_detection",
1535       true,
1536       "Detect Sequences",
1537       "Automatically detect animated sequences in selected images (based on file names)");
1538 }
1539
1540 /******************** Match movie length operator ********************/
1541 static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
1542 {
1543   Scene *scene = CTX_data_scene(C);
1544   Image *ima = image_from_context(C);
1545   ImageUser *iuser = image_user_from_context(C);
1546
1547   if (!ima || !iuser) {
1548     /* Try to get a Texture, or a SpaceImage from context... */
1549     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1550     if (tex && tex->type == TEX_IMAGE) {
1551       ima = tex->ima;
1552       iuser = &tex->iuser;
1553     }
1554   }
1555
1556   if (!ima || !iuser || !BKE_image_has_anim(ima)) {
1557     return OPERATOR_CANCELLED;
1558   }
1559
1560   struct anim *anim = ((ImageAnim *)ima->anims.first)->anim;
1561   if (!anim) {
1562     return OPERATOR_CANCELLED;
1563   }
1564   iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
1565   BKE_image_user_frame_calc(iuser, scene->r.cfra);
1566
1567   return OPERATOR_FINISHED;
1568 }
1569
1570 /* called by other space types too */
1571 void IMAGE_OT_match_movie_length(wmOperatorType *ot)
1572 {
1573   /* identifiers */
1574   ot->name = "Match Movie Length";
1575   ot->description = "Set image's user's length to the one of this video";
1576   ot->idname = "IMAGE_OT_match_movie_length";
1577
1578   /* api callbacks */
1579   ot->exec = image_match_len_exec;
1580
1581   /* flags */
1582   /* Don't think we need undo for that. */
1583   ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
1584 }
1585
1586 /******************** replace image operator ********************/
1587
1588 static int image_replace_exec(bContext *C, wmOperator *op)
1589 {
1590   Main *bmain = CTX_data_main(C);
1591   SpaceImage *sima = CTX_wm_space_image(C);
1592   char str[FILE_MAX];
1593
1594   if (!sima->image) {
1595     return OPERATOR_CANCELLED;
1596   }
1597
1598   RNA_string_get(op->ptr, "filepath", str);
1599
1600   /* we cant do much if the str is longer then FILE_MAX :/ */
1601   BLI_strncpy(sima->image->name, str, sizeof(sima->image->name));
1602
1603   if (sima->image->source == IMA_SRC_GENERATED) {
1604     sima->image->source = IMA_SRC_FILE;
1605     BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1606   }
1607
1608   if (BLI_path_extension_check_array(str, imb_ext_movie)) {
1609     sima->image->source = IMA_SRC_MOVIE;
1610   }
1611   else {
1612     sima->image->source = IMA_SRC_FILE;
1613   }
1614
1615   /* XXX unpackImage frees image buffers */
1616   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1617
1618   BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id));
1619   BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1620   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1621
1622   return OPERATOR_FINISHED;
1623 }
1624
1625 static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1626 {
1627   SpaceImage *sima = CTX_wm_space_image(C);
1628
1629   if (!sima->image) {
1630     return OPERATOR_CANCELLED;
1631   }
1632
1633   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1634     return image_replace_exec(C, op);
1635   }
1636
1637   if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
1638     RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->name));
1639   }
1640
1641   image_filesel(C, op, sima->image->name);
1642
1643   return OPERATOR_RUNNING_MODAL;
1644 }
1645
1646 void IMAGE_OT_replace(wmOperatorType *ot)
1647 {
1648   /* identifiers */
1649   ot->name = "Replace Image";
1650   ot->idname = "IMAGE_OT_replace";
1651   ot->description = "Replace current image by another one from disk";
1652
1653   /* api callbacks */
1654   ot->exec = image_replace_exec;
1655   ot->invoke = image_replace_invoke;
1656   ot->poll = image_not_packed_poll;
1657
1658   /* flags */
1659   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1660
1661   /* properties */
1662   WM_operator_properties_filesel(ot,
1663                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
1664                                  FILE_SPECIAL,
1665                                  FILE_OPENFILE,
1666                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
1667                                  FILE_DEFAULTDISPLAY,
1668                                  FILE_SORT_ALPHA);
1669 }
1670
1671 /******************** save image as operator ********************/
1672
1673 static char imtype_best_depth(ImBuf *ibuf, const char imtype)
1674 {
1675   const char depth_ok = BKE_imtype_valid_depths(imtype);
1676
1677   if (ibuf->rect_float) {
1678     if (depth_ok & R_IMF_CHAN_DEPTH_32) {
1679       return R_IMF_CHAN_DEPTH_32;
1680     }
1681     if (depth_ok & R_IMF_CHAN_DEPTH_24) {
1682       return R_IMF_CHAN_DEPTH_24;
1683     }
1684     if (depth_ok & R_IMF_CHAN_DEPTH_16) {
1685       return R_IMF_CHAN_DEPTH_16;
1686     }
1687     if (depth_ok & R_IMF_CHAN_DEPTH_12) {
1688       return R_IMF_CHAN_DEPTH_12;
1689     }
1690     return R_IMF_CHAN_DEPTH_8;
1691   }
1692   else {
1693     if (depth_ok & R_IMF_CHAN_DEPTH_8) {
1694       return R_IMF_CHAN_DEPTH_8;
1695     }
1696     if (depth_ok & R_IMF_CHAN_DEPTH_12) {
1697       return R_IMF_CHAN_DEPTH_12;
1698     }
1699     if (depth_ok & R_IMF_CHAN_DEPTH_16) {
1700       return R_IMF_CHAN_DEPTH_16;
1701     }
1702     if (depth_ok & R_IMF_CHAN_DEPTH_24) {
1703       return R_IMF_CHAN_DEPTH_24;
1704     }
1705     if (depth_ok & R_IMF_CHAN_DEPTH_32) {
1706       return R_IMF_CHAN_DEPTH_32;
1707     }
1708     return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
1709   }
1710 }
1711
1712 static int image_save_options_init(Main *bmain,
1713                                    ImageSaveOptions *opts,
1714                                    Image *ima,
1715                                    ImageUser *iuser,
1716                                    const bool guess_path,
1717                                    const bool save_as_render)
1718 {
1719   void *lock;
1720   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
1721
1722   if (ibuf) {
1723     Scene *scene = opts->scene;
1724     bool is_depth_set = false;
1725
1726     if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
1727       /* imtype */
1728       opts->im_format = scene->r.im_format;
1729       is_depth_set = true;
1730       if (!BKE_image_is_multiview(ima)) {
1731         /* In case multiview is disabled,
1732          * render settings would be invalid for render result in this area. */
1733         opts->im_format.stereo3d_format = *ima->stereo3d_format;
1734         opts->im_format.views_format = ima->views_format;
1735       }
1736     }
1737     else {
1738       if (ima->source == IMA_SRC_GENERATED) {
1739         opts->im_format.imtype = R_IMF_IMTYPE_PNG;
1740         opts->im_format.compress = ibuf->foptions.quality;
1741         opts->im_format.planes = ibuf->planes;
1742       }
1743       else {
1744         BKE_imbuf_to_image_format(&opts->im_format, ibuf);
1745       }
1746
1747       /* use the multiview image settings as the default */
1748       opts->im_format.stereo3d_format = *ima->stereo3d_format;
1749       opts->im_format.views_format = ima->views_format;
1750     }
1751
1752     ///* XXX - this is lame, we need to make these available too! */
1753     // opts->subimtype = scene->r.subimtype;
1754
1755     BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
1756
1757     /* sanitize all settings */
1758
1759     /* unlikely but just in case */
1760     if (ELEM(opts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
1761       opts->im_format.planes = R_IMF_PLANES_RGBA;
1762     }
1763
1764     /* depth, account for float buffer and format support */
1765     if (is_depth_set == false) {
1766       opts->im_format.depth = imtype_best_depth(ibuf, opts->im_format.imtype);
1767     }
1768
1769     /* some formats don't use quality so fallback to scenes quality */
1770     if (opts->im_format.quality == 0) {
1771       opts->im_format.quality = scene->r.im_format.quality;
1772     }
1773
1774     /* check for empty path */
1775     if (guess_path && opts->filepath[0] == 0) {
1776       const bool is_prev_save = !STREQ(G.ima, "//");
1777       if (save_as_render) {
1778         if (is_prev_save) {
1779           BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
1780         }
1781         else {
1782           BLI_strncpy(opts->filepath, "//untitled", sizeof(opts->filepath));
1783           BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
1784         }
1785       }
1786       else {
1787         BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
1788         BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
1789       }
1790     }
1791
1792     /* color management */
1793     BKE_color_managed_display_settings_copy(&opts->im_format.display_settings,
1794                                             &scene->display_settings);
1795     BKE_color_managed_view_settings_copy(&opts->im_format.view_settings, &scene->view_settings);
1796   }
1797
1798   BKE_image_release_ibuf(ima, ibuf, lock);
1799
1800   return (ibuf != NULL);
1801 }
1802
1803 static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOperator *op)
1804 {
1805   if (op->customdata) {
1806     BKE_color_managed_view_settings_free(&opts->im_format.view_settings);
1807
1808     opts->im_format = *(ImageFormatData *)op->customdata;
1809   }
1810
1811   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1812     RNA_string_get(op->ptr, "filepath", opts->filepath);
1813     BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
1814   }
1815 }
1816
1817 static void image_save_options_to_op(ImageSaveOptions *opts, wmOperator *op)
1818 {
1819   if (op->customdata) {
1820     BKE_color_managed_view_settings_free(&((ImageFormatData *)op->customdata)->view_settings);
1821
1822     *(ImageFormatData *)op->customdata = opts->im_format;
1823   }
1824
1825   RNA_string_set(op->ptr, "filepath", opts->filepath);
1826 }
1827
1828 static bool save_image_op(const bContext *C, wmOperator *op, ImageSaveOptions *opts)
1829 {
1830   Main *bmain = CTX_data_main(C);
1831   Image *ima = image_from_context(C);
1832   ImageUser *iuser = image_user_from_context(C);
1833
1834   opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") &&
1835                     RNA_boolean_get(op->ptr, "relative_path"));
1836   opts->save_copy = (RNA_struct_find_property(op->ptr, "copy") &&
1837                      RNA_boolean_get(op->ptr, "copy"));
1838   opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
1839                           RNA_boolean_get(op->ptr, "save_as_render"));
1840
1841   WM_cursor_wait(1);
1842
1843   bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
1844
1845   WM_cursor_wait(0);
1846
1847   /* Remember file path for next save. */
1848   BLI_strncpy(G.ima, opts->filepath, sizeof(G.ima));
1849
1850   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1851
1852   return ok;
1853 }
1854
1855 static void image_save_as_free(wmOperator *op)
1856 {
1857   if (op->customdata) {
1858     ImageFormatData *im_format = (ImageFormatData *)op->customdata;
1859     BKE_color_managed_view_settings_free(&im_format->view_settings);
1860
1861     MEM_freeN(op->customdata);
1862     op->customdata = NULL;
1863   }
1864 }
1865
1866 static int image_save_as_exec(bContext *C, wmOperator *op)
1867 {
1868   Main *bmain = CTX_data_main(C);
1869   Scene *scene = CTX_data_scene(C);
1870   Image *image = image_from_context(C);
1871   ImageUser *iuser = image_user_from_context(C);
1872   ImageSaveOptions opts;
1873
1874   BKE_image_save_options_init(&opts, bmain, scene);
1875
1876   /* just in case to initialize values,
1877    * these should be set on invoke or by the caller. */
1878   image_save_options_init(bmain, &opts, image, iuser, false, false);
1879
1880   image_save_options_from_op(bmain, &opts, op);
1881   opts.do_newpath = true;
1882
1883   save_image_op(C, op, &opts);
1884
1885   image_save_as_free(op);
1886   return OPERATOR_FINISHED;
1887 }
1888
1889 static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
1890 {
1891   ImageFormatData *imf = op->customdata;
1892   return WM_operator_filesel_ensure_ext_imtype(op, imf);
1893 }
1894
1895 static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1896 {
1897   Main *bmain = CTX_data_main(C);
1898   Image *ima = image_from_context(C);
1899   ImageUser *iuser = image_user_from_context(C);
1900   Scene *scene = CTX_data_scene(C);
1901   ImageSaveOptions opts;
1902   PropertyRNA *prop;
1903   const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) ||
1904                                (ima->flag & IMA_VIEW_AS_RENDER));
1905
1906   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1907     return image_save_as_exec(C, op);
1908   }
1909
1910   BKE_image_save_options_init(&opts, bmain, scene);
1911
1912   if (image_save_options_init(bmain, &opts, ima, iuser, true, save_as_render) == 0) {
1913     return OPERATOR_CANCELLED;
1914   }
1915   image_save_options_to_op(&opts, op);
1916
1917   /* enable save_copy by default for render results */
1918   if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) &&
1919       !RNA_struct_property_is_set(op->ptr, "copy")) {
1920     RNA_boolean_set(op->ptr, "copy", true);
1921   }
1922
1923   RNA_boolean_set(op->ptr, "save_as_render", save_as_render);
1924
1925   op->customdata = MEM_mallocN(sizeof(opts.im_format), __func__);
1926   memcpy(op->customdata, &opts.im_format, sizeof(opts.im_format));
1927
1928   /* show multiview save options only if image has multiviews */
1929   prop = RNA_struct_find_property(op->ptr, "show_multiview");
1930   RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
1931   prop = RNA_struct_find_property(op->ptr, "use_multiview");
1932   RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
1933
1934   image_filesel(C, op, opts.filepath);
1935
1936   return OPERATOR_RUNNING_MODAL;
1937 }
1938
1939 static void image_save_as_cancel(bContext *UNUSED(C), wmOperator *op)
1940 {
1941   image_save_as_free(op);
1942 }
1943
1944 static bool image_save_as_draw_check_prop(PointerRNA *ptr,
1945                                           PropertyRNA *prop,
1946                                           void *UNUSED(user_data))
1947 {
1948   const char *prop_id = RNA_property_identifier(prop);
1949
1950   return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
1951            STREQ(prop_id, "filename") ||
1952            /* when saving a copy, relative path has no effect */
1953            ((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy")));
1954 }
1955
1956 static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
1957 {
1958   uiLayout *layout = op->layout;
1959   ImageFormatData *imf = op->customdata;
1960   PointerRNA imf_ptr, ptr;
1961   const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
1962
1963   /* image template */
1964   RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1965   uiTemplateImageSettings(layout, &imf_ptr, false);
1966
1967   /* main draw call */
1968   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1969   uiDefAutoButsRNA(
1970       layout, &ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
1971
1972   /* multiview template */
1973   if (is_multiview) {
1974     uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1975   }
1976 }
1977
1978 static bool image_save_as_poll(bContext *C)
1979 {
1980   if (!image_buffer_exists_from_context(C)) {
1981     return false;
1982   }
1983
1984   if (G.is_rendering) {
1985     /* no need to NULL check here */
1986     Image *ima = image_from_context(C);
1987
1988     if (ima->source == IMA_SRC_VIEWER) {
1989       CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
1990       return false;
1991     }
1992   }
1993
1994   return true;
1995 }
1996
1997 void IMAGE_OT_save_as(wmOperatorType *ot)
1998 {
1999   /* identifiers */
2000   ot->name = "Save As Image";
2001   ot->idname = "IMAGE_OT_save_as";
2002   ot->description = "Save the image with another name and/or settings";
2003
2004   /* api callbacks */
2005   ot->exec = image_save_as_exec;
2006   ot->check = image_save_as_check;
2007   ot->invoke = image_save_as_invoke;
2008   ot->cancel = image_save_as_cancel;
2009   ot->ui = image_save_as_draw;
2010   ot->poll = image_save_as_poll;
2011
2012   /* flags */
2013   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2014
2015   /* properties */
2016   RNA_def_boolean(ot->srna,
2017                   "save_as_render",
2018                   0,
2019                   "Save As Render",
2020                   "Apply render part of display transform when saving byte image");
2021   RNA_def_boolean(ot->srna,
2022                   "copy",
2023                   0,
2024                   "Copy",
2025                   "Create a new image file without modifying the current image in blender");
2026
2027   WM_operator_properties_filesel(ot,
2028                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
2029                                  FILE_SPECIAL,
2030                                  FILE_SAVE,
2031                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
2032                                  FILE_DEFAULTDISPLAY,
2033                                  FILE_SORT_ALPHA);
2034 }
2035
2036 /******************** save image operator ********************/
2037
2038 static int image_save_exec(bContext *C, wmOperator *op)
2039 {
2040   Main *bmain = CTX_data_main(C);
2041   Image *image = image_from_context(C);
2042   ImageUser *iuser = image_user_from_context(C);
2043   Scene *scene = CTX_data_scene(C);
2044   ImageSaveOptions opts;
2045
2046   BKE_image_save_options_init(&opts, bmain, scene);
2047   if (image_save_options_init(bmain, &opts, image, iuser, false, false) == 0) {
2048     return OPERATOR_CANCELLED;
2049   }
2050   image_save_options_from_op(bmain, &opts, op);
2051
2052   if (BLI_exists(opts.filepath) && BLI_file_is_writable(opts.filepath)) {
2053     if (save_image_op(C, op, &opts)) {
2054       /* report since this can be called from key-shortcuts */
2055       BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", opts.filepath);
2056     }
2057   }
2058   else {
2059     BKE_reportf(
2060         op->reports, RPT_ERROR, "Cannot save image, path '%s' is not writable", opts.filepath);
2061     return OPERATOR_CANCELLED;
2062   }
2063
2064   return OPERATOR_FINISHED;
2065 }
2066
2067 static int image_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2068 {
2069   if (space_image_file_exists_poll(C)) {
2070     return image_save_exec(C, op);
2071   }
2072   else {
2073     WM_operator_name_call(C, "IMAGE_OT_save_as", WM_OP_INVOKE_DEFAULT, NULL);
2074     return OPERATOR_CANCELLED;
2075   }
2076 }
2077
2078 void IMAGE_OT_save(wmOperatorType *ot)
2079 {
2080   /* identifiers */
2081   ot->name = "Save Image";
2082   ot->idname = "IMAGE_OT_save";
2083   ot->description = "Save the image with current name and settings";
2084
2085   /* api callbacks */
2086   ot->exec = image_save_exec;
2087   ot->invoke = image_save_invoke;
2088   ot->poll = image_save_as_poll;
2089
2090   /* flags */
2091   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2092 }
2093
2094 /******************* save sequence operator ********************/
2095
2096 static int image_save_sequence_exec(bContext *C, wmOperator *op)
2097 {
2098   Main *bmain = CTX_data_main(C);
2099   Image *image = image_from_context(C);
2100   ImBuf *ibuf, *first_ibuf = NULL;
2101   int tot = 0;
2102   char di[FILE_MAX];
2103   struct MovieCacheIter *iter;
2104
2105   if (image == NULL) {
2106     return OPERATOR_CANCELLED;
2107   }
2108
2109   if (image->source != IMA_SRC_SEQUENCE) {
2110     BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2111     return OPERATOR_CANCELLED;
2112   }
2113
2114   if (image->type == IMA_TYPE_MULTILAYER) {
2115     BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2116     return OPERATOR_CANCELLED;
2117   }
2118
2119   /* get total dirty buffers and first dirty buffer which is used for menu */
2120   ibuf = NULL;
2121   if (image->cache != NULL) {
2122     iter = IMB_moviecacheIter_new(image->cache);
2123     while (!IMB_moviecacheIter_done(iter)) {
2124       ibuf = IMB_moviecacheIter_getImBuf(iter);
2125       if (ibuf->userflags & IB_BITMAPDIRTY) {
2126         if (first_ibuf == NULL) {
2127           first_ibuf = ibuf;
2128         }
2129         tot++;
2130       }
2131       IMB_moviecacheIter_step(iter);
2132     }
2133     IMB_moviecacheIter_free(iter);
2134   }
2135
2136   if (tot == 0) {
2137     BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2138     return OPERATOR_CANCELLED;
2139   }
2140
2141   /* get a filename for menu */
2142   BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
2143   BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2144
2145   iter = IMB_moviecacheIter_new(image->cache);
2146   while (!IMB_moviecacheIter_done(iter)) {
2147     ibuf = IMB_moviecacheIter_getImBuf(iter);
2148
2149     if (ibuf->userflags & IB_BITMAPDIRTY) {
2150       char name[FILE_MAX];
2151       BLI_strncpy(name, ibuf->name, sizeof(name));
2152
2153       BLI_path_abs(name, BKE_main_blendfile_path(bmain));
2154
2155       if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
2156         BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
2157         break;
2158       }
2159
2160       BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->name);
2161       ibuf->userflags &= ~IB_BITMAPDIRTY;
2162     }
2163
2164     IMB_moviecacheIter_step(iter);
2165   }
2166   IMB_moviecacheIter_free(iter);
2167
2168   return OPERATOR_FINISHED;
2169 }
2170
2171 void IMAGE_OT_save_sequence(wmOperatorType *ot)
2172 {
2173   /* identifiers */
2174   ot->name = "Save Sequence";
2175   ot->idname = "IMAGE_OT_save_sequence";
2176   ot->description = "Save a sequence of images";
2177
2178   /* api callbacks */
2179   ot->exec = image_save_sequence_exec;
2180   ot->poll = image_buffer_exists_from_context;
2181
2182   /* flags */
2183   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2184 }
2185
2186 /********************** save all operator **********************/
2187
2188 static bool image_should_be_saved_when_modified(Image *ima)
2189 {
2190   return !ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE);
2191 }
2192
2193 static bool image_should_be_saved(Image *ima)
2194 {
2195   if (BKE_image_is_dirty(ima) && (ima->source == IMA_SRC_FILE)) {
2196     return image_should_be_saved_when_modified(ima);
2197   }
2198   else {
2199     return false;
2200   }
2201 }
2202
2203 static bool image_has_valid_path(Image *ima)
2204 {
2205   return strchr(ima->name, '\\') || strchr(ima->name, '/');
2206 }
2207
2208 bool ED_image_should_save_modified(const bContext *C)
2209 {
2210   return ED_image_save_all_modified_info(C, NULL) > 0;
2211 }
2212
2213 int ED_image_save_all_modified_info(const bContext *C, ReportList *reports)
2214 {
2215   Main *bmain = CTX_data_main(C);
2216   GSet *unique_paths = BLI_gset_str_new(__func__);
2217
2218   int num_saveable_images = 0;
2219
2220   for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
2221     if (image_should_be_saved(ima)) {
2222       if (BKE_image_has_packedfile(ima)) {
2223         if (ima->id.lib == NULL) {
2224           num_saveable_images++;
2225         }
2226         else {
2227           BKE_reportf(reports,
2228                       RPT_WARNING,
2229                       "Packed library image: %s from library %s can't be saved",
2230                       ima->id.name,
2231                       ima->id.lib->name);
2232         }
2233       }
2234       else {
2235         if (image_has_valid_path(ima)) {
2236           num_saveable_images++;
2237           if (BLI_gset_haskey(unique_paths, ima->name)) {
2238             BKE_reportf(reports,
2239                         RPT_WARNING,
2240                         "File path used by more than one saved image: %s",
2241                         ima->name);
2242           }
2243           else {
2244             BLI_gset_insert(unique_paths, BLI_strdup(ima->name));
2245           }
2246         }
2247         else {
2248           BKE_reportf(reports,
2249                       RPT_WARNING,
2250                       "Image %s can't be saved, no valid file path: %s",
2251                       ima->id.name,
2252                       ima->name);
2253         }
2254       }
2255     }
2256   }
2257
2258   BLI_gset_free(unique_paths, MEM_freeN);
2259   return num_saveable_images;
2260 }
2261
2262 bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
2263 {
2264   ED_image_save_all_modified_info(C, reports);
2265
2266   Main *bmain = CTX_data_main(C);
2267   bool ok = true;
2268
2269   for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
2270     if (image_should_be_saved(ima)) {
2271       if (BKE_image_has_packedfile(ima)) {
2272         BKE_image_memorypack(ima);
2273       }
2274       else {
2275         if (image_has_valid_path(ima)) {
2276           ImageSaveOptions opts;
2277           Scene *scene = CTX_data_scene(C);
2278           BKE_image_save_options_init(&opts, bmain, scene);
2279           if (image_save_options_init(bmain, &opts, ima, NULL, false, false)) {
2280             bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts);
2281             ok = ok && saved_successfully;
2282           }
2283         }
2284       }
2285     }
2286   }
2287   return ok;
2288 }
2289
2290 static bool image_save_all_modified_poll(bContext *C)
2291 {
2292   int num_files = ED_image_save_all_modified_info(C, NULL);
2293   return num_files > 0;
2294 }
2295
2296 static int image_save_all_modified_exec(bContext *C, wmOperator *op)
2297 {
2298   ED_image_save_all_modified(C, op->reports);
2299   return OPERATOR_FINISHED;
2300 }
2301
2302 void IMAGE_OT_save_all_modified(wmOperatorType *ot)
2303 {
2304   /* identifiers */
2305   ot->name = "Save All Modified";
2306   ot->idname = "IMAGE_OT_save_all_modified";
2307   ot->description = "Save all modified images";
2308
2309   /* api callbacks */
2310   ot->exec = image_save_all_modified_exec;
2311   ot->poll = image_save_all_modified_poll;
2312
2313   /* flags */
2314   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2315 }
2316
2317 /******************** reload image operator ********************/
2318
2319 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
2320 {
2321   Main *bmain = CTX_data_main(C);
2322   Image *ima = image_from_context(C);
2323   ImageUser *iuser = image_user_from_context(C);
2324
2325   if (!ima) {
2326     return OPERATOR_CANCELLED;
2327   }
2328
2329   /* XXX unpackImage frees image buffers */
2330   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2331
2332   BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
2333   DEG_id_tag_update(&ima->id, 0);
2334
2335   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2336
2337   return OPERATOR_FINISHED;
2338 }
2339
2340 void IMAGE_OT_reload(wmOperatorType *ot)
2341 {
2342   /* identifiers */
2343   ot->name = "Reload Image";
2344   ot->idname = "IMAGE_OT_reload";
2345   ot->description = "Reload current image from disk";
2346
2347   /* api callbacks */
2348   ot->exec = image_reload_exec;
2349
2350   /* flags */
2351   ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2352 }
2353
2354 /********************** new image operator *********************/
2355 #define IMA_DEF_NAME N_("Untitled")
2356
2357 enum {
2358   GEN_CONTEXT_NONE = 0,
2359   GEN_CONTEXT_PAINT_CANVAS = 1,
2360   GEN_CONTEXT_PAINT_STENCIL = 2,
2361 };
2362
2363 typedef struct ImageNewData {
2364   PropertyPointerRNA pprop;
2365 } ImageNewData;
2366
2367 static ImageNewData *image_new_init(bContext *C, wmOperator *op)
2368 {
2369   if (op->customdata) {
2370     return op->customdata;
2371   }
2372
2373   ImageNewData *data = MEM_callocN(sizeof(ImageNewData), __func__);
2374   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2375   op->customdata = data;
2376   return data;
2377 }
2378
2379 static void image_new_free(wmOperator *op)
2380 {
2381   if (op->customdata) {
2382     MEM_freeN(op->customdata);
2383     op->customdata = NULL;
2384   }
2385 }
2386
2387 static int image_new_exec(bContext *C, wmOperator *op)
2388 {
2389   SpaceImage *sima;
2390   Object *obedit;
2391   Image *ima;
2392   Main *bmain;
2393   PropertyRNA *prop;
2394   char name_buffer[MAX_ID_NAME - 2];
2395   const char *name;
2396   float color[4];
2397   int width, height, floatbuf, gen_type, alpha;
2398   int stereo3d;
2399
2400   /* retrieve state */
2401   sima = CTX_wm_space_image(C);
2402   obedit = CTX_data_edit_object(C);
2403   bmain = CTX_data_main(C);
2404
2405   prop = RNA_struct_find_property(op->ptr, "name");
2406   RNA_property_string_get(op->ptr, prop, name_buffer);
2407   if (!RNA_property_is_set(op->ptr, prop)) {
2408     /* Default value, we can translate! */
2409     name = DATA_(name_buffer);
2410   }
2411   else {
2412     name = name_buffer;
2413   }
2414   width = RNA_int_get(op->ptr, "width");
2415   height = RNA_int_get(op->ptr, "height");
2416   floatbuf = RNA_boolean_get(op->ptr, "float");
2417   gen_type = RNA_enum_get(op->ptr, "generated_type");
2418   RNA_float_get_array(op->ptr, "color", color);
2419   alpha = RNA_boolean_get(op->ptr, "alpha");
2420   stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2421
2422   if (!alpha) {
2423     color[3] = 1.0f;
2424   }
2425
2426   ima = BKE_image_add_generated(
2427       bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
2428
2429   if (!ima) {
2430     image_new_free(op);
2431     return OPERATOR_CANCELLED;
2432   }
2433
2434   /* hook into UI */
2435   ImageNewData *data = image_new_init(C, op);
2436
2437   if (data->pprop.prop) {
2438     /* when creating new ID blocks, use is already 1, but RNA
2439      * pointer use also increases user, so this compensates it */
2440     id_us_min(&ima->id);
2441
2442     PointerRNA imaptr;
2443     RNA_id_pointer_create(&ima->id, &imaptr);
2444     RNA_property_pointer_set(NULL, &data->pprop.ptr, data->pprop.prop, imaptr);
2445     RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2446   }
2447   else if (sima) {
2448     ED_space_image_set(bmain, sima, obedit, ima, false);
2449   }
2450
2451   BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
2452
2453   WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
2454
2455   image_new_free(op);
2456
2457   return OPERATOR_FINISHED;
2458 }
2459
2460 static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2461 {
2462   /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2463   ImageNewData *data;
2464   op->customdata = data = MEM_callocN(sizeof(ImageNewData), __func__);
2465   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2466
2467   /* Better for user feedback. */
2468   RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2469   return WM_operator_props_dialog_popup(C, op, 300, 100);
2470 }
2471
2472 static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
2473 {
2474   uiLayout *split, *col[2];
2475   uiLayout *layout = op->layout;
2476   PointerRNA ptr;
2477 #if 0
2478   Scene *scene = CTX_data_scene(C);
2479   const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2480 #endif
2481
2482   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2483
2484   /* copy of WM_operator_props_dialog_popup() layout */
2485
2486   split = uiLayoutSplit(layout, 0.5f, false);
2487   col[0] = uiLayoutColumn(split, false);
2488   col[1] = uiLayoutColumn(split, false);
2489
2490   uiItemL(col[0], IFACE_("Name"), ICON_NONE);
2491   uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
2492
2493   uiItemL(col[0], IFACE_("Width"), ICON_NONE);
2494   uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
2495
2496   uiItemL(col[0], IFACE_("Height"), ICON_NONE);
2497   uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
2498
2499   uiItemL(col[0], IFACE_("Color"), ICON_NONE);
2500   uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
2501
2502   uiItemL(col[0], "", ICON_NONE);
2503   uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
2504
2505   uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
2506   uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
2507
2508   uiItemL(col[0], "", ICON_NONE);
2509   uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
2510
2511 #if 0
2512   if (is_multiview) {
2513     uiItemL(col[0], "", ICON_NONE);
2514     uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
2515   }
2516 #endif
2517 }
2518
2519 static void image_new_cancel(bContext *UNUSED(C), wmOperator *op)
2520 {
2521   image_new_free(op);
2522 }
2523
2524 void IMAGE_OT_new(wmOperatorType *ot)
2525 {
2526   PropertyRNA *prop;
2527   static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2528
2529   /* identifiers */
2530   ot->name = "New Image";
2531   ot->description = "Create a new image";
2532   ot->idname = "IMAGE_OT_new";
2533
2534   /* api callbacks */
2535   ot->exec = image_new_exec;
2536   ot->invoke = image_new_invoke;
2537   ot->ui = image_new_draw;
2538   ot->cancel = image_new_cancel;
2539
2540   /* flags */
2541   ot->flag = OPTYPE_UNDO;
2542
2543   /* properties */
2544   RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2545   prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2546   RNA_def_property_subtype(prop, PROP_PIXEL);
2547   prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2548   RNA_def_property_subtype(prop, PROP_PIXEL);
2549   prop = RNA_def_float_color(
2550       ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2551   RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
2552   RNA_def_property_float_array_default(prop, default_color);
2553   RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
2554   RNA_def_enum(ot->srna,
2555                "generated_type",
2556                rna_enum_image_generated_type_items,
2557                IMA_GENTYPE_BLANK,
2558                "Generated Type",
2559                "Fill the image with a grid for UV map testing");
2560   RNA_def_boolean(
2561       ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
2562   RNA_def_property_flag(prop, PROP_HIDDEN);
2563   prop = RNA_def_boolean(
2564       ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
2565   RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
2566 }
2567
2568 #undef IMA_DEF_NAME
2569
2570 /********************* invert operators *********************/
2571
2572 static bool image_invert_poll(bContext *C)
2573 {
2574   Image *ima = image_from_context(C);
2575
2576   return BKE_image_has_ibuf(ima, NULL);
2577 }
2578
2579 static int image_invert_exec(bContext *C, wmOperator *op)
2580 {
2581   Image *ima = image_from_context(C);
2582   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2583   SpaceImage *sima = CTX_wm_space_image(C);
2584   /* undo is supported only on image paint mode currently */
2585   bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2586
2587   /* flags indicate if this channel should be inverted */
2588   const bool r = RNA_boolean_get(op->ptr, "invert_r");
2589   const bool g = RNA_boolean_get(op->ptr, "invert_g");
2590   const bool b = RNA_boolean_get(op->ptr, "invert_b");
2591   const bool a = RNA_boolean_get(op->ptr, "invert_a");
2592
2593   size_t i;
2594
2595   if (ibuf == NULL) {
2596     /* TODO: this should actually never happen, but does for render-results -> cleanup */
2597     return OPERATOR_CANCELLED;
2598   }
2599
2600   if (support_undo) {
2601     ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
2602     /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
2603      * but better do this right in case someone copies this for a tool that uses partial
2604      * redraw better */
2605     ED_imapaint_clear_partial_redraw();
2606     ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
2607   }
2608   /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
2609   if (ibuf->rect_float) {
2610
2611     float *fp = (float *)ibuf->rect_float;
2612     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
2613       if (r) {
2614         fp[0] = 1.0f - fp[0];
2615       }
2616       if (g) {
2617         fp[1] = 1.0f - fp[1];
2618       }
2619       if (b) {
2620         fp[2] = 1.0f - fp[2];
2621       }
2622       if (a) {
2623         fp[3] = 1.0f - fp[3];
2624       }
2625     }
2626
2627     if (ibuf->rect) {
2628       IMB_rect_from_float(ibuf);
2629     }
2630   }
2631   else if (ibuf->rect) {
2632
2633     char *cp = (char *)ibuf->rect;
2634     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
2635       if (r) {
2636         cp[0] = 255 - cp[0];
2637       }
2638       if (g) {
2639         cp[1] = 255 - cp[1];
2640       }
2641       if (b) {
2642         cp[2] = 255 - cp[2];
2643       }
2644       if (a) {
2645         cp[3] = 255 - cp[3];
2646       }
2647     }
2648   }
2649   else {
2650     BKE_image_release_ibuf(ima, ibuf, NULL);
2651     return OPERATOR_CANCELLED;
2652   }
2653
2654   ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
2655   BKE_image_mark_dirty(ima, ibuf);
2656
2657   if (ibuf->mipmap[0]) {
2658     ibuf->userflags |= IB_MIPMAP_INVALID;
2659   }
2660
2661   if (support_undo) {
2662     ED_image_undo_push_end();
2663   }
2664
2665   /* force GPU reupload, all image is invalid */
2666   GPU_free_image(ima);
2667
2668   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2669
2670   BKE_image_release_ibuf(ima, ibuf, NULL);
2671
2672   return OPERATOR_FINISHED;
2673 }
2674
2675 void IMAGE_OT_invert(wmOperatorType *ot)
2676 {
2677   PropertyRNA *prop;
2678
2679   /* identifiers */
2680   ot->name = "Invert Channels";
2681   ot->idname = "IMAGE_OT_invert";
2682   ot->description = "Invert image's channels";
2683
2684   /* api callbacks */
2685   ot->exec = image_invert_exec;
2686   ot->poll = image_invert_poll;
2687
2688   /* properties */
2689   prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
2690   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2691   prop = RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel");
2692   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2693   prop = RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel");
2694   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2695   prop = RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel");
2696   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2697
2698   /* flags */
2699   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2700 }
2701
2702 /********************* pack operator *********************/
2703
2704 static bool image_pack_test(bContext *C, wmOperator *op)
2705 {
2706   Image *ima = image_from_context(C);
2707
2708   if (!ima) {
2709     return 0;
2710   }
2711
2712   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2713     BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
2714     return 0;
2715   }
2716
2717   return 1;
2718 }
2719
2720 static int image_pack_exec(bContext *C, wmOperator *op)
2721 {
2722   struct Main *bmain = CTX_data_main(C);
2723   Image *ima = image_from_context(C);
2724
2725   if (!image_pack_test(C, op)) {
2726     return OPERATOR_CANCELLED;
2727   }
2728
2729   if (BKE_image_is_dirty(ima)) {
2730     BKE_image_memorypack(ima);
2731   }
2732   else {
2733     BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
2734   }
2735
2736   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2737
2738   return OPERATOR_FINISHED;
2739 }
2740
2741 void IMAGE_OT_pack(wmOperatorType *ot)
2742 {
2743   /* identifiers */
2744   ot->name = "Pack Image";
2745   ot->description = "Pack an image as embedded data into the .blend file";
2746   ot->idname = "IMAGE_OT_pack";
2747
2748   /* api callbacks */
2749   ot->exec = image_pack_exec;
2750
2751   /* flags */
2752   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2753 }
2754
2755 /********************* unpack operator *********************/
2756
2757 static int image_unpack_exec(bContext *C, wmOperator *op)
2758 {
2759   Image *ima = image_from_context(C);
2760   int method = RNA_enum_get(op->ptr, "method");
2761
2762   /* find the suppplied image by name */
2763   if (RNA_struct_property_is_set(op->ptr, "id")) {
2764     char imaname[MAX_ID_NAME - 2];
2765     RNA_string_get(op->ptr, "id", imaname);
2766     ima = BLI_findstring(&CTX_data_main(C)->images, imaname, offsetof(ID, name) + 2);
2767     if (!ima) {
2768       ima = image_from_context(C);
2769     }
2770   }
2771
2772   if (!ima || !BKE_image_has_packedfile(ima)) {
2773     return OPERATOR_CANCELLED;
2774   }
2775
2776   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2777     BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2778     return OPERATOR_CANCELLED;
2779   }
2780
2781   if (G.fileflags & G_FILE_AUTOPACK) {
2782     BKE_report(op->reports,
2783                RPT_WARNING,
2784                "AutoPack is enabled, so image will be packed again on file save");
2785   }
2786
2787   /* XXX unpackImage frees image buffers */
2788   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2789
2790   unpackImage(CTX_data_main(C), op->reports, ima, method);
2791
2792   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2793
2794   return OPERATOR_FINISHED;
2795 }
2796
2797 static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2798 {
2799   Image *ima = image_from_context(C);
2800
2801   if (RNA_struct_property_is_set(op->ptr, "id")) {
2802     return image_unpack_exec(C, op);
2803   }
2804
2805   if (!ima || !BKE_image_has_packedfile(ima)) {
2806     return OPERATOR_CANCELLED;
2807   }
2808
2809   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2810     BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2811     return OPERATOR_CANCELLED;
2812   }
2813
2814   if (G.fileflags & G_FILE_AUTOPACK) {
2815     BKE_report(op->reports,
2816                RPT_WARNING,
2817                "AutoPack is enabled, so image will be packed again on file save");
2818   }
2819
2820   unpack_menu(C,
2821               "IMAGE_OT_unpack",
2822               ima->id.name + 2,
2823               ima->name,
2824               "textures",
2825               BKE_image_has_packedfile(ima) ?
2826                   ((ImagePackedFile *)ima->packedfiles.first)->packedfile :
2827                   NULL);
2828
2829   return OPERATOR_FINISHED;
2830 }
2831
2832 void IMAGE_OT_unpack(wmOperatorType *ot)
2833 {
2834   /* identifiers */
2835   ot->name = "Unpack Image";
2836   ot->description = "Save an image packed in the .blend file to disk";
2837   ot->idname = "IMAGE_OT_unpack";
2838
2839   /* api callbacks */
2840   ot->exec = image_unpack_exec;
2841   ot->invoke = image_unpack_invoke;
2842
2843   /* flags */
2844   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2845
2846   /* properties */
2847   RNA_def_enum(
2848       ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
2849   /* XXX, weak!, will fail with library, name collisions */
2850   RNA_def_string(
2851       ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
2852 }
2853
2854 /******************** sample image operator ********************/
2855
2856 typedef struct ImageSampleInfo {
2857   ARegionType *art;
2858   void *draw_handle;
2859   int x, y;
2860   int channels;
2861
2862   int width, height;
2863   int sample_size;
2864
2865   unsigned char col[4];
2866   float colf[4];
2867   float linearcol[4];
2868   int z;
2869   float zf;
2870
2871   unsigned char *colp;
2872   const float *colfp;
2873   int *zp;
2874   float *zfp;
2875
2876   bool draw;
2877   bool color_manage;
2878   int use_default_view;
2879 } ImageSampleInfo;
2880
2881 static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
2882 {
2883   ImageSampleInfo *info = arg_info;
2884   if (!info->draw) {
2885     return;
2886   }
2887
2888   Scene *scene = CTX_data_scene(C);
2889   ED_image_draw_info(scene,
2890                      ar,
2891                      info->color_manage,
2892                      info->use_default_view,
2893                      info->channels,
2894                      info->x,
2895                      info->y,
2896                      info->colp,
2897                      info->colfp,
2898                      info->linearcol,
2899                      info->zp,
2900                      info->zfp);
2901
2902   if (info->sample_size > 1) {
2903     const wmWindow *win = CTX_wm_window(C);
2904     const wmEvent *event = win->eventstate;
2905
2906     SpaceImage *sima = CTX_wm_space_image(C);
2907     GPUVertFormat *format = immVertexFormat();
2908     uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2909
2910     const float color[3] = {1, 1, 1};
2911     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
2912     immUniformColor3fv(color);
2913
2914     /* TODO(campbell): lock to pixels. */
2915     rctf sample_rect_fl;
2916     BLI_rctf_init_pt_radius(&sample_rect_fl,
2917                             (float[2]){event->x - ar->winrct.xmin, event->y - ar->winrct.ymin},
2918                             (float)(info->sample_size / 2.0f) * sima->zoom);
2919
2920     glEnable(GL_COLOR_LOGIC_OP);
2921     glLogicOp(GL_XOR);
2922     GPU_line_width(1.0f);
2923     imm_draw_box_wire_2d(pos,
2924                          (float)sample_rect_fl.xmin,
2925                          (float)sample_rect_fl.ymin,
2926                          (float)sample_rect_fl.xmax,
2927                          (float)sample_rect_fl.ymax);
2928     glDisable(GL_COLOR_LOGIC_OP);
2929
2930     immUnbindProgram();
2931   }
2932 }
2933
2934 /* Returns color in linear space, matching ED_space_node_color_sample(). */
2935 bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
2936 {
2937   void *lock;
2938   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2939   float fx, fy;
2940   bool ret = false;
2941
2942   if (ibuf == NULL) {
2943     ED_space_image_release_buffer(sima, ibuf, lock);
2944     return false;
2945   }
2946
2947   UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
2948
2949   if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2950     const float *fp;
2951     unsigned char *cp;
2952     int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2953
2954     CLAMP(x, 0, ibuf->x - 1);
2955     CLAMP(y, 0, ibuf->y - 1);
2956
2957     if (ibuf->rect_float) {
2958       fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
2959       copy_v3_v3(r_col, fp);
2960       ret = true;
2961     }
2962     else if (ibuf->rect) {
2963       cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
2964       rgb_uchar_to_float(r_col, cp);
2965       IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
2966       ret = true;
2967     }
2968   }
2969
2970   ED_space_image_release_buffer(sima, ibuf, lock);
2971   return ret;
2972 }
2973
2974 /* -------------------------------------------------------------------- */
2975 /** \name Image Pixel Sample
2976  * \{ */
2977
2978 static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
2979                                            const int coord[2],
2980                                            uchar r_col[4],
2981                                            float r_col_linear[4])
2982 {
2983   const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
2984   copy_v4_v4_uchar(r_col, cp);
2985   rgba_uchar_to_float(r_col_linear, r_col);
2986   IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
2987 }
2988
2989 static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
2990 {
2991   const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
2992   copy_v4_v4(r_col, cp);
2993 }
2994
2995 /** \} */
2996
2997 /* -------------------------------------------------------------------- */
2998 /** \name Image Pixel Region Sample
2999  * \{ */
3000
3001 static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
3002                                           const rcti *rect,
3003                                           uchar r_col[4],
3004                                           float r_col_linear[4])
3005 {
3006   uint col_accum_ub[4] = {0, 0, 0, 0};
3007   zero_v4(r_col_linear);
3008   int col_tot = 0;
3009   int coord[2];
3010   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
3011     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
3012       float col_temp_fl[4];
3013       uchar col_temp_ub[4];
3014       image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
3015       add_v4_v4(r_col_linear, col_temp_fl);
3016       col_accum_ub[0] += (uint)col_temp_ub[0];
3017       col_accum_ub[1] += (uint)col_temp_ub[1];
3018       col_accum_ub[2] += (uint)col_temp_ub[2];
3019       col_accum_ub[3] += (uint)col_temp_ub[3];
3020       col_tot += 1;
3021     }
3022   }
3023   mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
3024
3025   r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
3026   r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
3027   r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
3028   r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
3029 }
3030
3031 static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
3032 {
3033   zero_v4(r_col);
3034   int col_tot = 0;
3035   int coord[2];
3036   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
3037     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
3038       float col_temp_fl[4];
3039       image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
3040       add_v4_v4(r_col, col_temp_fl);
3041       col_tot += 1;
3042     }
3043   }
3044   mul_v4_fl(r_col, 1.0 / (float)col_tot);
3045 }
3046
3047 /** \} */
3048
3049 static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
3050 {
3051   SpaceImage *sima = CTX_wm_space_image(C);
3052   ARegion *ar = CTX_wm_region(C);
3053   void *lock;
3054   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
3055   ImageSampleInfo *info = op->customdata;
3056   float fx, fy;
3057   Scene *scene = CTX_data_scene(C);
3058   CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
3059
3060   if (ibuf == NULL) {
3061     ED_space_image_release_buffer(sima, ibuf, lock);
3062     info->draw = false;
3063     return;
3064   }
3065
3066   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
3067
3068   if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
3069     int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
3070     Image *image = ED_space_image(sima);
3071
3072     CLAMP(x, 0, ibuf->x - 1);
3073     CLAMP(y, 0, ibuf->y - 1);
3074
3075     info->width = ibuf->x;
3076     info->height = ibuf->y;
3077     info->x = x;
3078     info->y = y;
3079
3080     info->draw = true;
3081     info->channels = ibuf->channels;
3082
3083     info->colp = NULL;
3084     info->colfp = NULL;
3085     info->zp = NULL;
3086     info->zfp = NULL;
3087
3088     info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
3089
3090     rcti sample_rect;
3091     sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
3092     sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
3093     sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
3094     sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
3095
3096     if (ibuf->rect) {
3097       image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
3098       rgba_uchar_to_float(info->colf, info->col);
3099
3100       info->colp = info->col;
3101       info->colfp = info->colf;
3102       info->color_manage = true;
3103     }
3104     if (ibuf->rect_float) {
3105       image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
3106
3107       if (ibuf->channels == 4) {
3108         /* pass */
3109       }
3110       else if (ibuf->channels == 3) {
3111         info->colf[3] = 1.0f;
3112       }
3113       else {
3114         info->colf[1] = info->colf[0];
3115         info->colf[2] = info->colf[0];
3116         info->colf[3] = 1.0f;
3117       }
3118       info->colfp = info->colf;
3119
3120       copy_v4_v4(info->linearcol, info->colf);
3121
3122       info->color_manage = true;
3123     }
3124
3125     if (ibuf->zbuf) {
3126       /* TODO, blend depth (not urgent). */
3127       info->z = ibuf->zbuf[y * ibuf->x + x];
3128       info->zp = &info->z;
3129       if (ibuf->zbuf == (int *)ibuf->rect) {
3130         info->colp = NULL;
3131       }
3132     }
3133     if (ibuf->zbuf_float) {
3134       /* TODO, blend depth (not urgent). */
3135       info->zf = ibuf->zbuf_float[y * ibuf->x + x];
3136       info->zfp = &info->zf;
3137       if (ibuf->zbuf_float == ibuf->rect_float) {
3138         info->colfp = NULL;
3139       }
3140     }
3141
3142     if (curve_mapping && ibuf->channels == 4) {
3143       /* we reuse this callback for set curves point operators */
3144       if (RNA_struct_find_property(op->ptr, "point")) {
3145         int point = RNA_enum_get(op->ptr, "point");
3146
3147         if (point == 1) {
3148           curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
3149         }
3150         else if (point == 0) {
3151           curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
3152         }
3153         WM_event_add_notifier(C, NC_WINDOW, NULL);
3154       }
3155     }
3156
3157     // XXX node curve integration ..
3158 #if 0
3159     {
3160       ScrArea *sa, *cur = curarea;
3161
3162       node_curvemap_sample(fp); /* sends global to node editor */
3163       for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
3164         if (sa->spacetype == SPACE_NODE) {
3165           areawinset(sa->win);
3166           scrarea_do_windraw(sa);
3167         }
3168       }
3169       node_curvemap_sample(NULL); /* clears global in node editor */
3170       curarea = cur;
3171     }
3172 #endif
3173   }
3174   else {
3175     info->draw = 0;
3176   }
3177
3178   ED_space_image_release_buffer(sima, ibuf, lock);
3179   ED_area_tag_redraw(CTX_wm_area(C));
3180 }
3181
3182 static void image_sample_exit(bContext *C, wmOperator *op)
3183 {
3184   ImageSampleInfo *info = op->customdata;
3185
3186   ED_region_draw_cb_exit(info->art, info->draw_handle);
3187   ED_area_tag_redraw(CTX_wm_area(C));
3188   MEM_freeN(info);
3189 }
3190
3191 static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3192 {
3193   SpaceImage *sima = CTX_wm_space_image(C);
3194   ARegion *ar = CTX_wm_region(C);
3195   ImageSampleInfo *info;
3196
3197   if (ar->regiontype == RGN_TYPE_WINDOW) {
3198     if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
3199       return OPERATOR_PASS_THROUGH;
3200     }
3201   }
3202
3203   if (!ED_space_image_has_buffer(sima)) {
3204     return OPERATOR_CANCELLED;
3205   }
3206
3207   info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
3208
3209   info->art = ar->type;
3210   info->draw_handle = ED_region_draw_cb_activate(
3211       ar->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
3212   info->sample_size = RNA_int_get(op->ptr, "size");
3213   op->customdata = info;
3214
3215   image_sample_apply(C, op, event);
3216
3217   WM_event_add_modal_handler(C, op);
3218
3219   return OPERATOR_RUNNING_MODAL;
3220 }
3221
3222 static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
3223 {
3224   switch (event->type) {
3225     case LEFTMOUSE:
3226     case RIGHTMOUSE:  // XXX hardcoded
3227       if (event->val == KM_RELEASE) {
3228         image_sample_exit(C, op);
3229         return OPERATOR_CANCELLED;
3230       }
3231       break;
3232     case MOUSEMOVE:
3233       image_sample_apply(C, op, event);
3234       break;
3235   }
3236
3237   return OPERATOR_RUNNING_MODAL;
3238 }
3239
3240 static void image_sample_cancel(bContext *C, wmOperator *op)
3241 {
3242   image_sample_exit(C, op);
3243 }
3244
3245 void IMAGE_OT_sample(wmOperatorType *ot)
3246 {
3247   /* identifiers */
3248   ot->name = "Sample Color";
3249   ot->idname = "IMAGE_OT_sample";
3250   ot->description = "Use mouse to sample a color in current image";
3251
3252   /* api callbacks */
3253   ot->invoke = image_sample_invoke;
3254   ot->modal = image_sample_modal;
3255   ot->cancel = image_sample_cancel;
3256   ot->poll = image_sample_poll;
3257
3258   /* flags */
3259   ot->flag = OPTYPE_BLOCKING;
3260
3261   PropertyRNA *prop;
3262   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3263   RNA_def_property_subtype(prop, PROP_PIXEL);
3264   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3265 }
3266
3267 /******************** sample line operator ********************/
3268 static int image_sample_line_exec(bContext *C, wmOperator *op)
3269 {
3270   SpaceImage *sima = CTX_wm_space_image(C);
3271   ARegion *ar = CTX_wm_region(C);
3272   Scene *scene = CTX_data_scene(C);
3273
3274   int x_start = RNA_int_get(op->ptr, "xstart");
3275   int y_start = RNA_int_get(op->ptr, "ystart");
3276   int x_end = RNA_int_get(op->ptr, "xend");
3277   int y_end = RNA_int_get(op->ptr, "yend");
3278
3279   void *lock;
3280   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
3281   Histogram *hist = &sima->sample_line_hist;
3282
3283   float x1f, y1f, x2f, y2f;
3284
3285   if (ibuf == NULL) {
3286     ED_space_image_release_buffer(sima, ibuf, lock);
3287     return OPERATOR_CANCELLED;
3288   }
3289   /* hmmmm */
3290   if (ibuf->channels < 3) {
3291     ED_space_image_release_buffer(sima, ibuf, lock);
3292     return OPERATOR_CANCELLED;
3293   }
3294
3295   UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
3296   UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
3297
3298   hist->co[0][0] = x1f;
3299   hist->co[0][1] = y1f;
3300   hist->co[1][0] = x2f;
3301   hist->co[1][1] = y2f;
3302
3303   /* enable line drawing */
3304   hist->flag |= HISTO_FLAG_SAMPLELINE;
3305
3306   BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
3307
3308   /* reset y zoom */
3309   hist->ymax = 1.0f;
3310
3311   ED_space_image_release_buffer(sima, ibuf, lock);
3312
3313   ED_area_tag_redraw(CTX_wm_area(C));
3314
3315   return OPERATOR_FINISHED;
3316 }
3317
3318 static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3319 {
3320   SpaceImage *sima = CTX_wm_space_image(C);
3321
3322   Histogram *hist = &sima->sample_line_hist;
3323   hist->flag &= ~HISTO_FLAG_SAMPLELINE;
3324
3325   if (!ED_space_image_has_buffer(sima)) {
3326     return OPERATOR_CANCELLED;
3327   }
3328
3329   return WM_gesture_straightline_invoke(C, op, event);
3330 }
3331
3332 void IMAGE_OT_sample_line(wmOperatorType *ot)
3333 {
3334   /* identifiers */
3335   ot->name = "Sample Line";
3336   ot->idname = "IMAGE_OT_sample_line";
3337   ot->description = "Sample a line and show it in Scope panels";
3338
3339   /* api callbacks */
3340   ot->invoke = image_sample_line_invoke;
3341   ot->modal = WM_gesture_straightline_modal;
3342   ot->exec = image_sample_line_exec;
3343   ot->poll = space_image_main_region_poll;
3344   ot->cancel = WM_gesture_straightline_cancel;
3345
3346   /* flags */
3347   ot->flag = 0; /* no undo/register since this operates on the space */
3348
3349   WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
3350 }
3351
3352 /******************** set curve point operator ********************/
3353
3354 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
3355 {
3356   static const EnumPropertyItem point_items[] = {
3357       {0, "BLACK_POINT", 0, "Black Point", ""},
3358       {1, "WHITE_POINT", 0, "White Point", ""},
3359       {0, NULL, 0, NULL, NULL},
3360   };
3361
3362   /* identifiers */
3363   ot->name = "Set Curves Point";
3364   ot->idname = "IMAGE_OT_curves_point_set";
3365   ot->description = "Set black point or white point for curves";
3366
3367   /* flags */
3368   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3369
3370   /* api callbacks */
3371   ot->invoke = image_sample_invoke;
3372   ot->modal = image_sample_modal;
3373   ot->cancel = image_sample_cancel;
3374   ot->poll = space_image_main_area_not_uv_brush_poll;
3375
3376   /* properties */
3377   RNA_def_enum(
3378       ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3379
3380   PropertyRNA *prop;
3381   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3382   RNA_def_property_subtype(prop, PROP_PIXEL);
3383   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3384 }
3385
3386 /********************* cycle render slot operator *********************/
3387
3388 static bool image_cycle_render_slot_poll(bContext *C)
3389 {
3390   Image *ima = image_from_context(C);
3391
3392   return (ima && ima->type == IMA_TYPE_R_RESULT);
3393 }
3394
3395 static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
3396 {
3397   Image *ima = image_from_context(C);
3398   const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
3399
3400   if (!ED_image_slot_cycle(ima, direction)) {
3401     return OPERATOR_CANCELLED;
3402   }
3403
3404   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3405
3406   /* no undo push for browsing existing */
3407   RenderSlot *slot = BKE_image_get_renderslot(ima, ima->render_slot);
3408   if ((slot && slot->render) || ima->render_slot == ima->last_render_slot) {
3409     return OPERATOR_CANCELLED;
3410   }
3411
3412   return OPERATOR_FINISHED;
3413 }
3414
3415 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
3416 {
3417   /* identifiers */
3418   ot->name = "Cycle Render Slot";
3419   ot->idname = "IMAGE_OT_cycle_render_slot";
3420   ot->description = "Cycle through all non-void render slots";
3421
3422   /* api callbacks */
3423   ot->exec = image_cycle_render_slot_exec;
3424   ot->poll = image_cycle_render_slot_poll;
3425
3426   /* flags */
3427   ot->flag = OPTYPE_REGISTER;
3428
3429   RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
3430 }
3431
3432 /********************* clear render slot operator *********************/
3433
3434 static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3435 {
3436   SpaceImage *sima = CTX_wm_space_image(C);
3437   Image *ima = image_from_context(C);
3438
3439   if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
3440     return OPERATOR_CANCELLED;
3441   }
3442
3443   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3444
3445   return OPERATOR_FINISHED;
3446 }
3447
3448 void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
3449 {
3450   /* identifiers */
3451   ot->name = "Clear Render Slot";
3452   ot->idname = "IMAGE_OT_clear_render_slot";
3453   ot->description = "Clear the currently selected render slot";
3454
3455   /* api callbacks */
3456   ot->exec = image_clear_render_slot_exec;
3457   ot->poll = image_cycle_render_slot_poll;
3458
3459   /* flags */
3460   ot->flag = OPTYPE_REGISTER;
3461 }
3462
3463 /********************* add render slot operator *********************/
3464
3465 static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3466 {
3467   Image *ima = image_from_context(C);
3468
3469   RenderSlot *slot = BKE_image_add_renderslot(ima, NULL);
3470   ima->render_slot = BLI_findindex(&ima->renderslots, slot);
3471
3472   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3473
3474   return OPERATOR_FINISHED;
3475 }
3476
3477 void IMAGE_OT_add_render_slot(wmOperatorType *ot)
3478 {
3479   /* identifiers */
3480   ot->name = "Add Render Slot";
3481   ot->idname = "IMAGE_OT_add_render_slot";
3482   ot->description = "Add a new render slot";
3483
3484   /* api callbacks */
3485   ot->exec = image_add_render_slot_exec;
3486   ot->poll = image_cycle_render_slot_poll;
3487
3488   /* flags */
3489   ot->flag = OPTYPE_REGISTER;
3490 }
3491
3492 /********************* remove render slot operator *********************/
3493
3494 static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3495 {
3496   SpaceImage *sima = CTX_wm_space_image(C);
3497   Image *ima = image_from_context(C);
3498
3499   if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
3500     return OPERATOR_CANCELLED;
3501   }
3502
3503   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3504
3505   return OPERATOR_FINISHED;
3506 }
3507
3508 void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
3509 {
3510   /* identifiers */
3511   ot->name = "Remove Render Slot";
3512   ot->idname = "IMAGE_OT_remove_render_slot";
3513   ot->description = "Remove the current render slot";
3514
3515   /* api callbacks */
3516   ot->exec = image_remove_render_slot_exec;
3517   ot->poll = image_cycle_render_slot_poll;
3518
3519   /* flags */
3520   ot->flag = OPTYPE_REGISTER;
3521 }
3522
3523 /********************** change frame operator *********************/
3524
3525 static bool change_frame_poll(bContext *C)
3526 {
3527   /* prevent changes during render */
3528   if (G.is_rendering) {
3529     return 0;
3530   }
3531
3532   return space_image_main_region_poll(C);
3533 }
3534
3535 static void change_frame_apply(bContext *C, wmOperator *op)
3536 {
3537   Scene *scene = CTX_data_scene(C);
3538
3539   /* set the new frame number */
3540   CFRA = RNA_int_get(op->ptr, "frame");
3541   FRAMENUMBER_MIN_CLAMP(CFRA);
3542   SUBFRA = 0.0f;
3543
3544   /* do updates */
3545   BKE_sound_seek_scene(CTX_data_main(C), scene);
3546   WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
3547 }
3548
3549 static int change_frame_exec(bContext *C, wmOperator *op)
3550 {
3551   change_frame_apply(C, op);
3552
3553   return OPERATOR_FINISHED;
3554 }
3555
3556 static int frame_from_event(bContext *C, const wmEvent *event)
3557 {
3558   ARegion *ar = CTX_wm_region(C);
3559   Scene *scene = CTX_data_scene(C);
3560   int framenr = 0;
3561
3562   if (ar->regiontype == RGN_TYPE_WINDOW) {
3563     float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
3564
3565     framenr = sfra + event->mval[0] / framelen;
3566   }
3567   else {
3568     float viewx, viewy;
3569
3570     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
3571
3572     framenr = round_fl_to_int(viewx);
3573   }
3574
3575   return framenr;
3576 }
3577
3578 static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3579 {
3580   ARegion *ar = CTX_wm_region(C);
3581
3582   if (ar->regiontype == RGN_TYPE_WINDOW) {
3583     SpaceImage *sima = CTX_wm_space_image(C);
3584     if (event->mval[1] > 16 || !ED_space_image_show_cache(sima)) {
3585       return OPERATOR_PASS_THROUGH;
3586     }
3587   }
3588
3589   RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3590
3591   change_frame_apply(C, op);
3592
3593   /* add temp handler */
3594   WM_event_add_modal_handler(C, op);
3595
3596   return OPERATOR_RUNNING_MODAL;
3597 }
3598
3599 static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
3600 {
3601   switch (event->type) {
3602     case ESCKEY:
3603       return OPERATOR_FINISHED;
3604
3605     case MOUSEMOVE:
3606       RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3607       change_frame_apply(C, op);
3608       break;
3609
3610     case LEFTMOUSE:
3611     case RIGHTMOUSE:
3612       if (event->val == KM_RELEASE) {
3613         return OPERATOR_FINISHED;
3614       }
3615       break;
3616   }
3617
3618   return OPERATOR_RUNNING_MODAL;
3619 }
3620
3621 void IMAGE_OT_change_frame(wmOperatorType *ot)
3622 {
3623   /* identifiers */
3624   ot->name = "Change Frame";
3625   ot->idname = "IMAGE_OT_change_frame";
3626   ot->description = "Interactively change the current frame number";
3627
3628   /* api callbacks */
3629   ot->exec = change_frame_exec;
3630   ot->invoke = change_frame_invoke;
3631   ot->modal = change_frame_modal;
3632   ot->poll = change_frame_poll;
3633
3634   /* flags */
3635   ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
3636
3637   /* rna */
3638   RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
3639 }
3640
3641 /* Reload cached render results... */
3642 /* goes over all scenes, reads render layers */
3643 static int image_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
3644 {
3645   Main *bmain = CTX_data_main(C);
3646   Scene *scene = CTX_data_scene(C);
3647   SpaceImage *sima = CTX_wm_space_image(C);
3648   Image *ima;
3649
3650   ima = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
3651   if (sima->image == NULL) {
3652     ED_space_image_set(bmain, sima, NULL, ima, false);
3653   }
3654
3655   RE_ReadRenderResult(scene, scene);
3656
3657   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
3658   return OPERATOR_FINISHED;
3659 }
3660
3661 void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
3662 {
3663   ot->name = "Open Cached Render";
3664   ot->idname = "IMAGE_OT_read_viewlayers";
3665   ot->description = "Read all the current scene's view layers from cache, as needed";
3666
3667   ot->poll = space_image_main_region_poll;
3668   ot->exec = image_read_viewlayers_exec;
3669
3670   /* flags */
3671   ot->flag = 0;
3672 }
3673
3674 /* ********************* Render border operator ****************** */
3675
3676 static int render_border_exec(bContext *C, wmOperator *op)
3677 {
3678   ARegion *ar = CTX_wm_region(C);
3679   Scene *scene = CTX_data_scene(C);
3680   Render *re = RE_GetSceneRender(scene);
3681   RenderData *rd;
3682   rctf border;
3683
3684   if (re == NULL) {
3685     /* Shouldn't happen, but better be safe close to the release. */
3686     return OPERATOR_CANCELLED;
3687   }
3688
3689   rd = RE_engine_get_render_data(re);
3690   if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
3691     BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render");
3692     return OPERATOR_CANCELLED;
3693   }
3694
3695   /* get rectangle from operator */
3696   WM_operator_properties_border_to_rctf(op, &border);
3697   UI_view2d_region_to_view_rctf(&ar->v2d, &border, &border);
3698
3699   /* actually set border */
3700   CLAMP(border.xmin, 0.0f, 1.0f);
3701   CLAMP(border.ymin, 0.0f, 1.0f);
3702   CLAMP(border.xmax, 0.0f, 1.0f);
3703   CLAMP(border.ymax, 0.0f, 1.0f);
3704   scene->r.border = border;
3705
3706   /* drawing a border surrounding the entire camera view switches off border rendering
3707    * or the border covers no pixels */
3708   if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
3709       (border.xmin == border.xmax || border.ymin == border.ymax)) {
3710     scene->r.mode &= ~R_BORDER;
3711   }
3712   else {
3713     scene->r.mode |= R_BORDER;
3714   }
3715
3716   DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
3717   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3718
3719   return OPERATOR_FINISHED;
3720 }
3721
3722 void IMAGE_OT_render_border(wmOperatorType *ot)
3723 {
3724   /* identifiers */
3725   ot->name = "Render Region";
3726   ot->description = "Set the boundaries of the render region and enable render region";
3727   ot->idname = "IMAGE_OT_render_border";
3728
3729   /* api callbacks */
3730   ot->invoke = WM_gesture_box_invoke;
3731   ot->exec = render_border_exec;
3732   ot->modal = WM_gesture_box_modal;
3733   ot->cancel = WM_gesture_box_cancel;
3734   ot->poll = image_cycle_render_slot_poll;
3735
3736   /* flags */
3737   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3738
3739   /* rna */
3740   WM_operator_properties_border(ot);
3741 }
3742
3743 /* ********************* Clear render border operator ****************** */
3744
3745 static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
3746 {
3747   Scene *scene = CTX_data_scene(C);
3748   scene->r.mode &= ~R_BORDER;
3749   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3750   BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
3751   return OPERATOR_FINISHED;
3752 }
3753
3754 void IMAGE_OT_clear_render_border(wmOperatorType *ot)
3755 {
3756   /* identifiers */
3757   ot->name = "Clear Render Region";
3758   ot->description = "Clear the boundaries of the render region and disable render region";
3759   ot->idname = "IMAGE_OT_clear_render_border";
3760
3761   /* api callbacks */
3762   ot->exec = clear_render_border_exec;
3763   ot->poll = image_cycle_render_slot_poll;
3764
3765   /* flags */
3766   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3767 }