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