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  * \brief 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 the first one by name
1123  */
1124 static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
1125 {
1126   char dir[FILE_MAXDIR];
1127   const bool do_frame_range = RNA_boolean_get(ptr, "use_sequence_detection");
1128   ImageFrameRange *frame_range = NULL;
1129
1130   RNA_string_get(ptr, "directory", dir);
1131   RNA_BEGIN (ptr, itemptr, "files") {
1132     char base_head[FILE_MAX], base_tail[FILE_MAX];
1133     char head[FILE_MAX], tail[FILE_MAX];
1134     unsigned short digits;
1135     char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
1136     ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
1137
1138     /* use the first file in the list as base filename */
1139     frame->framenr = BLI_stringdec(filename, head, tail, &digits);
1140
1141     /* still in the same sequence */
1142     if (do_frame_range && (frame_range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) &&
1143         (STREQLEN(base_tail, tail, FILE_MAX))) {
1144       /* pass */
1145     }
1146     else {
1147       /* start a new frame range */
1148       frame_range = MEM_callocN(sizeof(*frame_range), __func__);
1149       BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename);
1150       BLI_addtail(frames_all, frame_range);
1151
1152       BLI_strncpy(base_head, head, sizeof(base_head));
1153       BLI_strncpy(base_tail, tail, sizeof(base_tail));
1154     }
1155
1156     BLI_addtail(&frame_range->frames, frame);
1157     MEM_freeN(filename);
1158   }
1159   RNA_END;
1160 }
1161
1162 static int image_cmp_frame(const void *a, const void *b)
1163 {
1164   const ImageFrame *frame_a = a;
1165   const ImageFrame *frame_b = b;
1166
1167   if (frame_a->framenr < frame_b->framenr) {
1168     return -1;
1169   }
1170   if (frame_a->framenr > frame_b->framenr) {
1171     return 1;
1172   }
1173   return 0;
1174 }
1175
1176 /**
1177  * Return the start (offset) and the length of the sequence of continuous frames in the list of frames
1178  *
1179  * \param frames: [in] the list of frame numbers, as a side-effect the list is sorted.
1180  * \param ofs: [out] offset the first frame number in the sequence.
1181  * \return the number of contiguous frames in the sequence
1182  */
1183 static int image_sequence_get_len(ListBase *frames, int *ofs)
1184 {
1185   ImageFrame *frame;
1186
1187   BLI_listbase_sort(frames, image_cmp_frame);
1188
1189   frame = frames->first;
1190   if (frame) {
1191     int frame_curr = frame->framenr;
1192     (*ofs) = frame_curr;
1193     while (frame && (frame->framenr == frame_curr)) {
1194       frame_curr++;
1195       frame = frame->next;
1196     }
1197     return frame_curr - (*ofs);
1198   }
1199   *ofs = 0;
1200   return 0;
1201 }
1202
1203 static Image *image_open_single(Main *bmain,
1204                                 wmOperator *op,
1205                                 const char *filepath,
1206                                 const char *relbase,
1207                                 bool is_relative_path,
1208                                 bool use_multiview,
1209                                 int frame_seq_len)
1210 {
1211   bool exists = false;
1212   Image *ima = NULL;
1213
1214   errno = 0;
1215   ima = BKE_image_load_exists_ex(bmain, filepath, &exists);
1216
1217   if (!ima) {
1218     if (op->customdata) {
1219       MEM_freeN(op->customdata);
1220     }
1221     BKE_reportf(op->reports,
1222                 RPT_ERROR,
1223                 "Cannot read '%s': %s",
1224                 filepath,
1225                 errno ? strerror(errno) : TIP_("unsupported image format"));
1226     return NULL;
1227   }
1228
1229   if (!exists) {
1230     /* only image path after save, never ibuf */
1231     if (is_relative_path) {
1232       BLI_path_rel(ima->name, relbase);
1233     }
1234
1235     /* handle multiview images */
1236     if (use_multiview) {
1237       ImageOpenData *iod = op->customdata;
1238       ImageFormatData *imf = &iod->im_format;
1239
1240       ima->flag |= IMA_USE_VIEWS;
1241       ima->views_format = imf->views_format;
1242       *ima->stereo3d_format = imf->stereo3d_format;
1243     }
1244     else {
1245       ima->flag &= ~IMA_USE_VIEWS;
1246       BKE_image_free_views(ima);
1247     }
1248
1249     if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
1250       ima->source = IMA_SRC_SEQUENCE;
1251     }
1252   }
1253
1254   return ima;
1255 }
1256
1257 static int image_open_exec(bContext *C, wmOperator *op)
1258 {
1259   Main *bmain = CTX_data_main(C);
1260   ScrArea *sa = CTX_wm_area(C);
1261   Scene *scene = CTX_data_scene(C);
1262   Object *obedit = CTX_data_edit_object(C);
1263   ImageUser *iuser = NULL;
1264   ImageOpenData *iod = op->customdata;
1265   Image *ima = NULL;
1266   char filepath[FILE_MAX];
1267   int frame_seq_len = 0;
1268   int frame_ofs = 1;
1269
1270   const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
1271   const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
1272
1273   if (!op->customdata) {
1274     image_open_init(C, op);
1275   }
1276
1277   RNA_string_get(op->ptr, "filepath", filepath);
1278
1279   if (RNA_struct_property_is_set(op->ptr, "directory") &&
1280       RNA_struct_property_is_set(op->ptr, "files")) {
1281     bool was_relative = BLI_path_is_rel(filepath);
1282     ListBase frame_ranges_all;
1283
1284     BLI_listbase_clear(&frame_ranges_all);
1285     image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
1286     for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range;
1287          frame_range = frame_range->next) {
1288       int frame_range_ofs;
1289       int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
1290       BLI_freelistN(&frame_range->frames);
1291
1292       char filepath_range[FILE_MAX];
1293       BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
1294
1295       if (was_relative) {
1296         BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
1297       }
1298
1299       Image *ima_range = image_open_single(bmain,
1300                                            op,
1301                                            filepath_range,
1302                                            BKE_main_blendfile_path(bmain),
1303                                            is_relative_path,
1304                                            use_multiview,
1305                                            frame_range_seq_len);
1306
1307       /* take the first image */
1308       if ((ima == NULL) && ima_range) {
1309         ima = ima_range;
1310         frame_seq_len = frame_range_seq_len;
1311         frame_ofs = frame_range_ofs;
1312       }
1313     }
1314     BLI_freelistN(&frame_ranges_all);
1315   }
1316   else {
1317     /* for drag & drop etc. */
1318     ima = image_open_single(
1319         bmain, op, filepath, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview, 1);
1320   }
1321
1322   if (ima == NULL) {
1323     return OPERATOR_CANCELLED;
1324   }
1325
1326   /* hook into UI */
1327   iod = op->customdata;
1328
1329   if (iod->pprop.prop) {
1330     /* when creating new ID blocks, use is already 1, but RNA
1331      * pointer use also increases user, so this compensates it */
1332     id_us_min(&ima->id);
1333
1334     PointerRNA imaptr;
1335     RNA_id_pointer_create(&ima->id, &imaptr);
1336     RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr);
1337     RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1338   }
1339
1340   if (iod->iuser) {
1341     iuser = iod->iuser;
1342   }
1343   else if (sa && sa->spacetype == SPACE_IMAGE) {
1344     SpaceImage *sima = sa->spacedata.first;
1345     ED_space_image_set(bmain, sima, obedit, ima, false);
1346     iuser = &sima->iuser;
1347   }
1348   else {
1349     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1350     if (tex && tex->type == TEX_IMAGE) {
1351       iuser = &tex->iuser;
1352     }
1353
1354     if (iuser == NULL) {
1355       Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
1356       if (cam) {
1357         for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
1358           if (bgpic->ima == ima) {
1359             iuser = &bgpic->iuser;
1360             break;
1361           }
1362         }
1363       }
1364     }
1365   }
1366
1367   /* initialize because of new image */
1368   if (iuser) {
1369     iuser->frames = frame_seq_len;
1370     iuser->sfra = 1;
1371     iuser->framenr = 1;
1372     if (ima->source == IMA_SRC_MOVIE) {
1373       iuser->offset = 0;
1374     }
1375     else {
1376       iuser->offset = frame_ofs - 1;
1377     }
1378     iuser->scene = scene;
1379     BKE_image_init_imageuser(ima, iuser);
1380   }
1381
1382   /* XXX unpackImage frees image buffers */
1383   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1384
1385   BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
1386   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1387
1388   MEM_freeN(op->customdata);
1389
1390   return OPERATOR_FINISHED;
1391 }
1392
1393 static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1394 {
1395   SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1396   const char *path = U.textudir;
1397   Image *ima = NULL;
1398   Scene *scene = CTX_data_scene(C);
1399
1400   if (sima) {
1401     ima = sima->image;
1402   }
1403
1404   if (ima == NULL) {
1405     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1406     if (tex && tex->type == TEX_IMAGE) {
1407       ima = tex->ima;
1408     }
1409   }
1410
1411   if (ima == NULL) {
1412     PointerRNA ptr;
1413     PropertyRNA *prop;
1414
1415     /* hook into UI */
1416     UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
1417
1418     if (prop) {
1419       PointerRNA oldptr;
1420       Image *oldima;
1421
1422       oldptr = RNA_property_pointer_get(&ptr, prop);
1423       oldima = (Image *)oldptr.id.data;
1424       /* unlikely to fail but better avoid strange crash */
1425       if (oldima && GS(oldima->id.name) == ID_IM) {
1426         ima = oldima;
1427       }
1428     }
1429   }
1430
1431   if (ima) {
1432     path = ima->name;
1433   }
1434
1435   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1436     return image_open_exec(C, op);
1437   }
1438
1439   image_open_init(C, op);
1440
1441   /* show multiview save options only if scene has multiviews */
1442   PropertyRNA *prop;
1443   prop = RNA_struct_find_property(op->ptr, "show_multiview");
1444   RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1445
1446   image_filesel(C, op, path);
1447
1448   return OPERATOR_RUNNING_MODAL;
1449 }
1450
1451 static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr),
1452                                        PropertyRNA *prop,
1453                                        void *UNUSED(user_data))
1454 {
1455   const char *prop_id = RNA_property_identifier(prop);
1456
1457   return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
1458            STREQ(prop_id, "filename"));
1459 }
1460
1461 static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
1462 {
1463   uiLayout *layout = op->layout;
1464   ImageOpenData *iod = op->customdata;
1465   ImageFormatData *imf = &iod->im_format;
1466   PointerRNA imf_ptr, ptr;
1467
1468   /* main draw call */
1469   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1470   uiDefAutoButsRNA(
1471       layout, &ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
1472
1473   /* image template */
1474   RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1475
1476   /* multiview template */
1477   if (RNA_boolean_get(op->ptr, "show_multiview")) {
1478     uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1479   }
1480 }
1481
1482 /* called by other space types too */
1483 void IMAGE_OT_open(wmOperatorType *ot)
1484 {
1485   /* identifiers */
1486   ot->name = "Open Image";
1487   ot->description = "Open image";
1488   ot->idname = "IMAGE_OT_open";
1489
1490   /* api callbacks */
1491   ot->exec = image_open_exec;
1492   ot->invoke = image_open_invoke;
1493   ot->cancel = image_open_cancel;
1494   ot->ui = image_open_draw;
1495
1496   /* flags */
1497   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1498
1499   /* properties */
1500   WM_operator_properties_filesel(ot,
1501                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
1502                                  FILE_SPECIAL,
1503                                  FILE_OPENFILE,
1504                                  WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES |
1505                                      WM_FILESEL_RELPATH,
1506                                  FILE_DEFAULTDISPLAY,
1507                                  FILE_SORT_ALPHA);
1508
1509   RNA_def_boolean(
1510       ot->srna,
1511       "use_sequence_detection",
1512       true,
1513       "Detect Sequences",
1514       "Automatically detect animated sequences in selected images (based on file names)");
1515 }
1516
1517 /******************** Match movie length operator ********************/
1518 static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
1519 {
1520   Scene *scene = CTX_data_scene(C);
1521   Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data;
1522   ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data;
1523
1524   if (!ima || !iuser) {
1525     /* Try to get a Texture, or a SpaceImage from context... */
1526     SpaceImage *sima = CTX_wm_space_image(C);
1527     Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1528     if (tex && tex->type == TEX_IMAGE) {
1529       ima = tex->ima;
1530       iuser = &tex->iuser;
1531     }
1532     else if (sima) {
1533       ima = sima->image;
1534       iuser = &sima->iuser;
1535     }
1536   }
1537
1538   if (!ima || !iuser || !BKE_image_has_anim(ima)) {
1539     return OPERATOR_CANCELLED;
1540   }
1541
1542   struct anim *anim = ((ImageAnim *)ima->anims.first)->anim;
1543   if (!anim) {
1544     return OPERATOR_CANCELLED;
1545   }
1546   iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
1547   BKE_image_user_frame_calc(iuser, scene->r.cfra);
1548
1549   return OPERATOR_FINISHED;
1550 }
1551
1552 /* called by other space types too */
1553 void IMAGE_OT_match_movie_length(wmOperatorType *ot)
1554 {
1555   /* identifiers */
1556   ot->name = "Match Movie Length";
1557   ot->description = "Set image's user's length to the one of this video";
1558   ot->idname = "IMAGE_OT_match_movie_length";
1559
1560   /* api callbacks */
1561   ot->exec = image_match_len_exec;
1562
1563   /* flags */
1564   /* Don't think we need undo for that. */
1565   ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
1566 }
1567
1568 /******************** replace image operator ********************/
1569
1570 static int image_replace_exec(bContext *C, wmOperator *op)
1571 {
1572   Main *bmain = CTX_data_main(C);
1573   SpaceImage *sima = CTX_wm_space_image(C);
1574   char str[FILE_MAX];
1575
1576   if (!sima->image) {
1577     return OPERATOR_CANCELLED;
1578   }
1579
1580   RNA_string_get(op->ptr, "filepath", str);
1581
1582   /* we cant do much if the str is longer then FILE_MAX :/ */
1583   BLI_strncpy(sima->image->name, str, sizeof(sima->image->name));
1584
1585   if (sima->image->source == IMA_SRC_GENERATED) {
1586     sima->image->source = IMA_SRC_FILE;
1587     BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1588   }
1589
1590   if (BLI_path_extension_check_array(str, imb_ext_movie)) {
1591     sima->image->source = IMA_SRC_MOVIE;
1592   }
1593   else {
1594     sima->image->source = IMA_SRC_FILE;
1595   }
1596
1597   /* XXX unpackImage frees image buffers */
1598   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1599
1600   BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id));
1601   BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1602   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1603
1604   return OPERATOR_FINISHED;
1605 }
1606
1607 static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1608 {
1609   SpaceImage *sima = CTX_wm_space_image(C);
1610
1611   if (!sima->image) {
1612     return OPERATOR_CANCELLED;
1613   }
1614
1615   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1616     return image_replace_exec(C, op);
1617   }
1618
1619   if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
1620     RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->name));
1621   }
1622
1623   image_filesel(C, op, sima->image->name);
1624
1625   return OPERATOR_RUNNING_MODAL;
1626 }
1627
1628 void IMAGE_OT_replace(wmOperatorType *ot)
1629 {
1630   /* identifiers */
1631   ot->name = "Replace Image";
1632   ot->idname = "IMAGE_OT_replace";
1633   ot->description = "Replace current image by another one from disk";
1634
1635   /* api callbacks */
1636   ot->exec = image_replace_exec;
1637   ot->invoke = image_replace_invoke;
1638   ot->poll = image_not_packed_poll;
1639
1640   /* flags */
1641   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1642
1643   /* properties */
1644   WM_operator_properties_filesel(ot,
1645                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
1646                                  FILE_SPECIAL,
1647                                  FILE_OPENFILE,
1648                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
1649                                  FILE_DEFAULTDISPLAY,
1650                                  FILE_SORT_ALPHA);
1651 }
1652
1653 /******************** save image as operator ********************/
1654
1655 static char imtype_best_depth(ImBuf *ibuf, const char imtype)
1656 {
1657   const char depth_ok = BKE_imtype_valid_depths(imtype);
1658
1659   if (ibuf->rect_float) {
1660     if (depth_ok & R_IMF_CHAN_DEPTH_32) {
1661       return R_IMF_CHAN_DEPTH_32;
1662     }
1663     if (depth_ok & R_IMF_CHAN_DEPTH_24) {
1664       return R_IMF_CHAN_DEPTH_24;
1665     }
1666     if (depth_ok & R_IMF_CHAN_DEPTH_16) {
1667       return R_IMF_CHAN_DEPTH_16;
1668     }
1669     if (depth_ok & R_IMF_CHAN_DEPTH_12) {
1670       return R_IMF_CHAN_DEPTH_12;
1671     }
1672     return R_IMF_CHAN_DEPTH_8;
1673   }
1674   else {
1675     if (depth_ok & R_IMF_CHAN_DEPTH_8) {
1676       return R_IMF_CHAN_DEPTH_8;
1677     }
1678     if (depth_ok & R_IMF_CHAN_DEPTH_12) {
1679       return R_IMF_CHAN_DEPTH_12;
1680     }
1681     if (depth_ok & R_IMF_CHAN_DEPTH_16) {
1682       return R_IMF_CHAN_DEPTH_16;
1683     }
1684     if (depth_ok & R_IMF_CHAN_DEPTH_24) {
1685       return R_IMF_CHAN_DEPTH_24;
1686     }
1687     if (depth_ok & R_IMF_CHAN_DEPTH_32) {
1688       return R_IMF_CHAN_DEPTH_32;
1689     }
1690     return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
1691   }
1692 }
1693
1694 static int image_save_options_init(Main *bmain,
1695                                    ImageSaveOptions *opts,
1696                                    Image *ima,
1697                                    ImageUser *iuser,
1698                                    const bool guess_path,
1699                                    const bool save_as_render)
1700 {
1701   void *lock;
1702   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
1703
1704   if (ibuf) {
1705     Scene *scene = opts->scene;
1706     bool is_depth_set = false;
1707
1708     if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
1709       /* imtype */
1710       opts->im_format = scene->r.im_format;
1711       is_depth_set = true;
1712       if (!BKE_image_is_multiview(ima)) {
1713         /* In case multiview is disabled,
1714          * render settings would be invalid for render result in this area. */
1715         opts->im_format.stereo3d_format = *ima->stereo3d_format;
1716         opts->im_format.views_format = ima->views_format;
1717       }
1718     }
1719     else {
1720       if (ima->source == IMA_SRC_GENERATED) {
1721         opts->im_format.imtype = R_IMF_IMTYPE_PNG;
1722         opts->im_format.compress = ibuf->foptions.quality;
1723         opts->im_format.planes = ibuf->planes;
1724       }
1725       else {
1726         BKE_imbuf_to_image_format(&opts->im_format, ibuf);
1727       }
1728
1729       /* use the multiview image settings as the default */
1730       opts->im_format.stereo3d_format = *ima->stereo3d_format;
1731       opts->im_format.views_format = ima->views_format;
1732     }
1733
1734     ///* XXX - this is lame, we need to make these available too! */
1735     //opts->subimtype = scene->r.subimtype;
1736
1737     BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
1738
1739     /* sanitize all settings */
1740
1741     /* unlikely but just in case */
1742     if (ELEM(opts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
1743       opts->im_format.planes = R_IMF_PLANES_RGBA;
1744     }
1745
1746     /* depth, account for float buffer and format support */
1747     if (is_depth_set == false) {
1748       opts->im_format.depth = imtype_best_depth(ibuf, opts->im_format.imtype);
1749     }
1750
1751     /* some formats don't use quality so fallback to scenes quality */
1752     if (opts->im_format.quality == 0) {
1753       opts->im_format.quality = scene->r.im_format.quality;
1754     }
1755
1756     /* check for empty path */
1757     if (guess_path && opts->filepath[0] == 0) {
1758       const bool is_prev_save = !STREQ(G.ima, "//");
1759       if (save_as_render) {
1760         if (is_prev_save) {
1761           BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
1762         }
1763         else {
1764           BLI_strncpy(opts->filepath, "//untitled", sizeof(opts->filepath));
1765           BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
1766         }
1767       }
1768       else {
1769         BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
1770         BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
1771       }
1772     }
1773
1774     /* color management */
1775     BKE_color_managed_display_settings_copy(&opts->im_format.display_settings,
1776                                             &scene->display_settings);
1777     BKE_color_managed_view_settings_copy(&opts->im_format.view_settings, &scene->view_settings);
1778   }
1779
1780   BKE_image_release_ibuf(ima, ibuf, lock);
1781
1782   return (ibuf != NULL);
1783 }
1784
1785 static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOperator *op)
1786 {
1787   if (op->customdata) {
1788     BKE_color_managed_view_settings_free(&opts->im_format.view_settings);
1789
1790     opts->im_format = *(ImageFormatData *)op->customdata;
1791   }
1792
1793   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1794     RNA_string_get(op->ptr, "filepath", opts->filepath);
1795     BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
1796   }
1797 }
1798
1799 static void image_save_options_to_op(ImageSaveOptions *opts, wmOperator *op)
1800 {
1801   if (op->customdata) {
1802     BKE_color_managed_view_settings_free(&((ImageFormatData *)op->customdata)->view_settings);
1803
1804     *(ImageFormatData *)op->customdata = opts->im_format;
1805   }
1806
1807   RNA_string_set(op->ptr, "filepath", opts->filepath);
1808 }
1809
1810 static bool save_image_op(const bContext *C,
1811                           SpaceImage *sima,
1812                           wmOperator *op,
1813                           ImageSaveOptions *opts)
1814 {
1815   Main *bmain = CTX_data_main(C);
1816   Image *ima = ED_space_image(sima);
1817   ImageUser *iuser = &sima->iuser;
1818
1819   opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") &&
1820                     RNA_boolean_get(op->ptr, "relative_path"));
1821   opts->save_copy = (RNA_struct_find_property(op->ptr, "copy") &&
1822                      RNA_boolean_get(op->ptr, "copy"));
1823   opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
1824                           RNA_boolean_get(op->ptr, "save_as_render"));
1825
1826   WM_cursor_wait(1);
1827
1828   bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
1829
1830   WM_cursor_wait(0);
1831
1832   /* Remember file path for next save. */
1833   BLI_strncpy(G.ima, opts->filepath, sizeof(G.ima));
1834
1835   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1836
1837   return ok;
1838 }
1839
1840 static void image_save_as_free(wmOperator *op)
1841 {
1842   if (op->customdata) {
1843     ImageFormatData *im_format = (ImageFormatData *)op->customdata;
1844     BKE_color_managed_view_settings_free(&im_format->view_settings);
1845
1846     MEM_freeN(op->customdata);
1847     op->customdata = NULL;
1848   }
1849 }
1850
1851 static int image_save_as_exec(bContext *C, wmOperator *op)
1852 {
1853   Main *bmain = CTX_data_main(C);
1854   Scene *scene = CTX_data_scene(C);
1855   SpaceImage *sima = CTX_wm_space_image(C);
1856   ImageSaveOptions opts;
1857
1858   BKE_image_save_options_init(&opts, bmain, scene);
1859
1860   /* just in case to initialize values,
1861    * these should be set on invoke or by the caller. */
1862   image_save_options_init(bmain, &opts, sima->image, &sima->iuser, false, false);
1863
1864   image_save_options_from_op(bmain, &opts, op);
1865   opts.do_newpath = true;
1866
1867   save_image_op(C, sima, op, &opts);
1868
1869   image_save_as_free(op);
1870   return OPERATOR_FINISHED;
1871 }
1872
1873 static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
1874 {
1875   ImageFormatData *imf = op->customdata;
1876   return WM_operator_filesel_ensure_ext_imtype(op, imf);
1877 }
1878
1879 static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1880 {
1881   Main *bmain = CTX_data_main(C);
1882   SpaceImage *sima = CTX_wm_space_image(C);
1883   Image *ima = ED_space_image(sima);
1884   Scene *scene = CTX_data_scene(C);
1885   ImageSaveOptions opts;
1886   PropertyRNA *prop;
1887   const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) ||
1888                                (ima->flag & IMA_VIEW_AS_RENDER));
1889
1890   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1891     return image_save_as_exec(C, op);
1892   }
1893
1894   BKE_image_save_options_init(&opts, bmain, scene);
1895
1896   if (image_save_options_init(bmain, &opts, ima, &sima->iuser, true, save_as_render) == 0) {
1897     return OPERATOR_CANCELLED;
1898   }
1899   image_save_options_to_op(&opts, op);
1900
1901   /* enable save_copy by default for render results */
1902   if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) &&
1903       !RNA_struct_property_is_set(op->ptr, "copy")) {
1904     RNA_boolean_set(op->ptr, "copy", true);
1905   }
1906
1907   RNA_boolean_set(op->ptr, "save_as_render", save_as_render);
1908
1909   op->customdata = MEM_mallocN(sizeof(opts.im_format), __func__);
1910   memcpy(op->customdata, &opts.im_format, sizeof(opts.im_format));
1911
1912   /* show multiview save options only if image has multiviews */
1913   prop = RNA_struct_find_property(op->ptr, "show_multiview");
1914   RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
1915   prop = RNA_struct_find_property(op->ptr, "use_multiview");
1916   RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
1917
1918   image_filesel(C, op, opts.filepath);
1919
1920   return OPERATOR_RUNNING_MODAL;
1921 }
1922
1923 static void image_save_as_cancel(bContext *UNUSED(C), wmOperator *op)
1924 {
1925   image_save_as_free(op);
1926 }
1927
1928 static bool image_save_as_draw_check_prop(PointerRNA *ptr,
1929                                           PropertyRNA *prop,
1930                                           void *UNUSED(user_data))
1931 {
1932   const char *prop_id = RNA_property_identifier(prop);
1933
1934   return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
1935            STREQ(prop_id, "filename") ||
1936            /* when saving a copy, relative path has no effect */
1937            ((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy")));
1938 }
1939
1940 static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
1941 {
1942   uiLayout *layout = op->layout;
1943   ImageFormatData *imf = op->customdata;
1944   PointerRNA imf_ptr, ptr;
1945   const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
1946
1947   /* image template */
1948   RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1949   uiTemplateImageSettings(layout, &imf_ptr, false);
1950
1951   /* main draw call */
1952   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1953   uiDefAutoButsRNA(
1954       layout, &ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
1955
1956   /* multiview template */
1957   if (is_multiview) {
1958     uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1959   }
1960 }
1961
1962 static bool image_save_as_poll(bContext *C)
1963 {
1964   if (space_image_buffer_exists_poll(C)) {
1965     if (G.is_rendering) {
1966       /* no need to NULL check here */
1967       SpaceImage *sima = CTX_wm_space_image(C);
1968       Image *ima = ED_space_image(sima);
1969
1970       if (ima->source == IMA_SRC_VIEWER) {
1971         CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
1972         return false;
1973       }
1974     }
1975     return true;
1976   }
1977   return false;
1978 }
1979
1980 void IMAGE_OT_save_as(wmOperatorType *ot)
1981 {
1982   /* identifiers */
1983   ot->name = "Save As Image";
1984   ot->idname = "IMAGE_OT_save_as";
1985   ot->description = "Save the image with another name and/or settings";
1986
1987   /* api callbacks */
1988   ot->exec = image_save_as_exec;
1989   ot->check = image_save_as_check;
1990   ot->invoke = image_save_as_invoke;
1991   ot->cancel = image_save_as_cancel;
1992   ot->ui = image_save_as_draw;
1993   ot->poll = image_save_as_poll;
1994
1995   /* flags */
1996   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1997
1998   /* properties */
1999   RNA_def_boolean(ot->srna,
2000                   "save_as_render",
2001                   0,
2002                   "Save As Render",
2003                   "Apply render part of display transform when saving byte image");
2004   RNA_def_boolean(ot->srna,
2005                   "copy",
2006                   0,
2007                   "Copy",
2008                   "Create a new image file without modifying the current image in blender");
2009
2010   WM_operator_properties_filesel(ot,
2011                                  FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
2012                                  FILE_SPECIAL,
2013                                  FILE_SAVE,
2014                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
2015                                  FILE_DEFAULTDISPLAY,
2016                                  FILE_SORT_ALPHA);
2017 }
2018
2019 /******************** save image operator ********************/
2020
2021 static int image_save_exec(bContext *C, wmOperator *op)
2022 {
2023   Main *bmain = CTX_data_main(C);
2024   SpaceImage *sima = CTX_wm_space_image(C);
2025   Scene *scene = CTX_data_scene(C);
2026   ImageSaveOptions opts;
2027
2028   BKE_image_save_options_init(&opts, bmain, scene);
2029   if (image_save_options_init(bmain, &opts, sima->image, &sima->iuser, false, false) == 0) {
2030     return OPERATOR_CANCELLED;
2031   }
2032   image_save_options_from_op(bmain, &opts, op);
2033
2034   if (BLI_exists(opts.filepath) && BLI_file_is_writable(opts.filepath)) {
2035     if (save_image_op(C, sima, op, &opts)) {
2036       /* report since this can be called from key-shortcuts */
2037       BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", opts.filepath);
2038     }
2039   }
2040   else {
2041     BKE_reportf(
2042         op->reports, RPT_ERROR, "Cannot save image, path '%s' is not writable", opts.filepath);
2043     return OPERATOR_CANCELLED;
2044   }
2045
2046   return OPERATOR_FINISHED;
2047 }
2048
2049 void IMAGE_OT_save(wmOperatorType *ot)
2050 {
2051   /* identifiers */
2052   ot->name = "Save Image";
2053   ot->idname = "IMAGE_OT_save";
2054   ot->description = "Save the image with current name and settings";
2055
2056   /* api callbacks */
2057   ot->exec = image_save_exec;
2058   ot->poll = space_image_file_exists_poll;
2059
2060   /* flags */
2061   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2062 }
2063
2064 /******************* save sequence operator ********************/
2065
2066 static int image_save_sequence_exec(bContext *C, wmOperator *op)
2067 {
2068   Main *bmain = CTX_data_main(C);
2069   SpaceImage *sima = CTX_wm_space_image(C);
2070   ImBuf *ibuf, *first_ibuf = NULL;
2071   int tot = 0;
2072   char di[FILE_MAX];
2073   struct MovieCacheIter *iter;
2074
2075   if (sima->image == NULL) {
2076     return OPERATOR_CANCELLED;
2077   }
2078
2079   if (sima->image->source != IMA_SRC_SEQUENCE) {
2080     BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2081     return OPERATOR_CANCELLED;
2082   }
2083
2084   if (sima->image->type == IMA_TYPE_MULTILAYER) {
2085     BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2086     return OPERATOR_CANCELLED;
2087   }
2088
2089   /* get total dirty buffers and first dirty buffer which is used for menu */
2090   ibuf = NULL;
2091   if (sima->image->cache != NULL) {
2092     iter = IMB_moviecacheIter_new(sima->image->cache);
2093     while (!IMB_moviecacheIter_done(iter)) {
2094       ibuf = IMB_moviecacheIter_getImBuf(iter);
2095       if (ibuf->userflags & IB_BITMAPDIRTY) {
2096         if (first_ibuf == NULL) {
2097           first_ibuf = ibuf;
2098         }
2099         tot++;
2100       }
2101       IMB_moviecacheIter_step(iter);
2102     }
2103     IMB_moviecacheIter_free(iter);
2104   }
2105
2106   if (tot == 0) {
2107     BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2108     return OPERATOR_CANCELLED;
2109   }
2110
2111   /* get a filename for menu */
2112   BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
2113   BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2114
2115   iter = IMB_moviecacheIter_new(sima->image->cache);
2116   while (!IMB_moviecacheIter_done(iter)) {
2117     ibuf = IMB_moviecacheIter_getImBuf(iter);
2118
2119     if (ibuf->userflags & IB_BITMAPDIRTY) {
2120       char name[FILE_MAX];
2121       BLI_strncpy(name, ibuf->name, sizeof(name));
2122
2123       BLI_path_abs(name, BKE_main_blendfile_path(bmain));
2124
2125       if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
2126         BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
2127         break;
2128       }
2129
2130       BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->name);
2131       ibuf->userflags &= ~IB_BITMAPDIRTY;
2132     }
2133
2134     IMB_moviecacheIter_step(iter);
2135   }
2136   IMB_moviecacheIter_free(iter);
2137
2138   return OPERATOR_FINISHED;
2139 }
2140
2141 void IMAGE_OT_save_sequence(wmOperatorType *ot)
2142 {
2143   /* identifiers */
2144   ot->name = "Save Sequence";
2145   ot->idname = "IMAGE_OT_save_sequence";
2146   ot->description = "Save a sequence of images";
2147
2148   /* api callbacks */
2149   ot->exec = image_save_sequence_exec;
2150   ot->poll = space_image_buffer_exists_poll;
2151
2152   /* flags */
2153   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2154 }
2155
2156 /******************** reload image operator ********************/
2157
2158 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
2159 {
2160   Main *bmain = CTX_data_main(C);
2161   Image *ima = CTX_data_edit_image(C);
2162   SpaceImage *sima = CTX_wm_space_image(C);
2163
2164   if (!ima) {
2165     return OPERATOR_CANCELLED;
2166   }
2167
2168   /* XXX unpackImage frees image buffers */
2169   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2170
2171   BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
2172   DEG_id_tag_update(&ima->id, 0);
2173
2174   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2175
2176   return OPERATOR_FINISHED;
2177 }
2178
2179 void IMAGE_OT_reload(wmOperatorType *ot)
2180 {
2181   /* identifiers */
2182   ot->name = "Reload Image";
2183   ot->idname = "IMAGE_OT_reload";
2184   ot->description = "Reload current image from disk";
2185
2186   /* api callbacks */
2187   ot->exec = image_reload_exec;
2188
2189   /* flags */
2190   ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2191 }
2192
2193 /********************** new image operator *********************/
2194 #define IMA_DEF_NAME N_("Untitled")
2195
2196 enum {
2197   GEN_CONTEXT_NONE = 0,
2198   GEN_CONTEXT_PAINT_CANVAS = 1,
2199   GEN_CONTEXT_PAINT_STENCIL = 2,
2200 };
2201
2202 typedef struct ImageNewData {
2203   PropertyPointerRNA pprop;
2204 } ImageNewData;
2205
2206 static ImageNewData *image_new_init(bContext *C, wmOperator *op)
2207 {
2208   if (op->customdata) {
2209     return op->customdata;
2210   }
2211
2212   ImageNewData *data = MEM_callocN(sizeof(ImageNewData), __func__);
2213   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2214   op->customdata = data;
2215   return data;
2216 }
2217
2218 static void image_new_free(wmOperator *op)
2219 {
2220   if (op->customdata) {
2221     MEM_freeN(op->customdata);
2222     op->customdata = NULL;
2223   }
2224 }
2225
2226 static int image_new_exec(bContext *C, wmOperator *op)
2227 {
2228   SpaceImage *sima;
2229   Object *obedit;
2230   Image *ima;
2231   Main *bmain;
2232   PropertyRNA *prop;
2233   char name_buffer[MAX_ID_NAME - 2];
2234   const char *name;
2235   float color[4];
2236   int width, height, floatbuf, gen_type, alpha;
2237   int stereo3d;
2238
2239   /* retrieve state */
2240   sima = CTX_wm_space_image(C);
2241   obedit = CTX_data_edit_object(C);
2242   bmain = CTX_data_main(C);
2243
2244   prop = RNA_struct_find_property(op->ptr, "name");
2245   RNA_property_string_get(op->ptr, prop, name_buffer);
2246   if (!RNA_property_is_set(op->ptr, prop)) {
2247     /* Default value, we can translate! */
2248     name = DATA_(name_buffer);
2249   }
2250   else {
2251     name = name_buffer;
2252   }
2253   width = RNA_int_get(op->ptr, "width");
2254   height = RNA_int_get(op->ptr, "height");
2255   floatbuf = RNA_boolean_get(op->ptr, "float");
2256   gen_type = RNA_enum_get(op->ptr, "generated_type");
2257   RNA_float_get_array(op->ptr, "color", color);
2258   alpha = RNA_boolean_get(op->ptr, "alpha");
2259   stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2260
2261   if (!alpha) {
2262     color[3] = 1.0f;
2263   }
2264
2265   ima = BKE_image_add_generated(
2266       bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
2267
2268   if (!ima) {
2269     image_new_free(op);
2270     return OPERATOR_CANCELLED;
2271   }
2272
2273   /* hook into UI */
2274   ImageNewData *data = image_new_init(C, op);
2275
2276   if (data->pprop.prop) {
2277     /* when creating new ID blocks, use is already 1, but RNA
2278      * pointer use also increases user, so this compensates it */
2279     id_us_min(&ima->id);
2280
2281     PointerRNA imaptr;
2282     RNA_id_pointer_create(&ima->id, &imaptr);
2283     RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr);
2284     RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2285   }
2286   else if (sima) {
2287     ED_space_image_set(bmain, sima, obedit, ima, false);
2288   }
2289
2290   BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
2291
2292   WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
2293
2294   image_new_free(op);
2295
2296   return OPERATOR_FINISHED;
2297 }
2298
2299 static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2300 {
2301   /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2302   ImageNewData *data;
2303   op->customdata = data = MEM_callocN(sizeof(ImageNewData), __func__);
2304   UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2305
2306   /* Better for user feedback. */
2307   RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2308   return WM_operator_props_dialog_popup(C, op, 300, 100);
2309 }
2310
2311 static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
2312 {
2313   uiLayout *split, *col[2];
2314   uiLayout *layout = op->layout;
2315   PointerRNA ptr;
2316 #if 0
2317   Scene *scene = CTX_data_scene(C);
2318   const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2319 #endif
2320
2321   RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2322
2323   /* copy of WM_operator_props_dialog_popup() layout */
2324
2325   split = uiLayoutSplit(layout, 0.5f, false);
2326   col[0] = uiLayoutColumn(split, false);
2327   col[1] = uiLayoutColumn(split, false);
2328
2329   uiItemL(col[0], IFACE_("Name"), ICON_NONE);
2330   uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
2331
2332   uiItemL(col[0], IFACE_("Width"), ICON_NONE);
2333   uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
2334
2335   uiItemL(col[0], IFACE_("Height"), ICON_NONE);
2336   uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
2337
2338   uiItemL(col[0], IFACE_("Color"), ICON_NONE);
2339   uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
2340
2341   uiItemL(col[0], "", ICON_NONE);
2342   uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
2343
2344   uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
2345   uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
2346
2347   uiItemL(col[0], "", ICON_NONE);
2348   uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
2349
2350 #if 0
2351   if (is_multiview) {
2352     uiItemL(col[0], "", ICON_NONE);
2353     uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
2354   }
2355 #endif
2356 }
2357
2358 static void image_new_cancel(bContext *UNUSED(C), wmOperator *op)
2359 {
2360   image_new_free(op);
2361 }
2362
2363 void IMAGE_OT_new(wmOperatorType *ot)
2364 {
2365   PropertyRNA *prop;
2366   static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2367
2368   /* identifiers */
2369   ot->name = "New Image";
2370   ot->description = "Create a new image";
2371   ot->idname = "IMAGE_OT_new";
2372
2373   /* api callbacks */
2374   ot->exec = image_new_exec;
2375   ot->invoke = image_new_invoke;
2376   ot->ui = image_new_draw;
2377   ot->cancel = image_new_cancel;
2378
2379   /* flags */
2380   ot->flag = OPTYPE_UNDO;
2381
2382   /* properties */
2383   RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2384   prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2385   RNA_def_property_subtype(prop, PROP_PIXEL);
2386   prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2387   RNA_def_property_subtype(prop, PROP_PIXEL);
2388   prop = RNA_def_float_color(
2389       ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2390   RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
2391   RNA_def_property_float_array_default(prop, default_color);
2392   RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
2393   RNA_def_enum(ot->srna,
2394                "generated_type",
2395                rna_enum_image_generated_type_items,
2396                IMA_GENTYPE_BLANK,
2397                "Generated Type",
2398                "Fill the image with a grid for UV map testing");
2399   RNA_def_boolean(
2400       ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
2401   RNA_def_property_flag(prop, PROP_HIDDEN);
2402   prop = RNA_def_boolean(
2403       ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
2404   RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
2405 }
2406
2407 #undef IMA_DEF_NAME
2408
2409 /********************* invert operators *********************/
2410
2411 static bool image_invert_poll(bContext *C)
2412 {
2413   Image *ima = CTX_data_edit_image(C);
2414
2415   return BKE_image_has_ibuf(ima, NULL);
2416 }
2417
2418 static int image_invert_exec(bContext *C, wmOperator *op)
2419 {
2420   Image *ima = CTX_data_edit_image(C);
2421   ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2422   SpaceImage *sima = CTX_wm_space_image(C);
2423   /* undo is supported only on image paint mode currently */
2424   bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2425
2426   /* flags indicate if this channel should be inverted */
2427   const bool r = RNA_boolean_get(op->ptr, "invert_r");
2428   const bool g = RNA_boolean_get(op->ptr, "invert_g");
2429   const bool b = RNA_boolean_get(op->ptr, "invert_b");
2430   const bool a = RNA_boolean_get(op->ptr, "invert_a");
2431
2432   size_t i;
2433
2434   if (ibuf == NULL) {
2435     /* TODO: this should actually never happen, but does for render-results -> cleanup */
2436     return OPERATOR_CANCELLED;
2437   }
2438
2439   if (support_undo) {
2440     ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
2441     /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
2442      * but better do this right in case someone copies this for a tool that uses partial
2443      * redraw better */
2444     ED_imapaint_clear_partial_redraw();
2445     ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
2446   }
2447   /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
2448   if (ibuf->rect_float) {
2449
2450     float *fp = (float *)ibuf->rect_float;
2451     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
2452       if (r) {
2453         fp[0] = 1.0f - fp[0];
2454       }
2455       if (g) {
2456         fp[1] = 1.0f - fp[1];
2457       }
2458       if (b) {
2459         fp[2] = 1.0f - fp[2];
2460       }
2461       if (a) {
2462         fp[3] = 1.0f - fp[3];
2463       }
2464     }
2465
2466     if (ibuf->rect) {
2467       IMB_rect_from_float(ibuf);
2468     }
2469   }
2470   else if (ibuf->rect) {
2471
2472     char *cp = (char *)ibuf->rect;
2473     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
2474       if (r) {
2475         cp[0] = 255 - cp[0];
2476       }
2477       if (g) {
2478         cp[1] = 255 - cp[1];
2479       }
2480       if (b) {
2481         cp[2] = 255 - cp[2];
2482       }
2483       if (a) {
2484         cp[3] = 255 - cp[3];
2485       }
2486     }
2487   }
2488   else {
2489     BKE_image_release_ibuf(ima, ibuf, NULL);
2490     return OPERATOR_CANCELLED;
2491   }
2492
2493   ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;
2494
2495   if (ibuf->mipmap[0]) {
2496     ibuf->userflags |= IB_MIPMAP_INVALID;
2497   }
2498
2499   if (support_undo) {
2500     ED_image_undo_push_end();
2501   }
2502
2503   /* force GPU reupload, all image is invalid */
2504   GPU_free_image(ima);
2505
2506   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2507
2508   BKE_image_release_ibuf(ima, ibuf, NULL);
2509
2510   return OPERATOR_FINISHED;
2511 }
2512
2513 void IMAGE_OT_invert(wmOperatorType *ot)
2514 {
2515   PropertyRNA *prop;
2516
2517   /* identifiers */
2518   ot->name = "Invert Channels";
2519   ot->idname = "IMAGE_OT_invert";
2520   ot->description = "Invert image's channels";
2521
2522   /* api callbacks */
2523   ot->exec = image_invert_exec;
2524   ot->poll = image_invert_poll;
2525
2526   /* properties */
2527   prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
2528   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2529   prop = RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel");
2530   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2531   prop = RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel");
2532   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2533   prop = RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel");
2534   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2535
2536   /* flags */
2537   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2538 }
2539
2540 /********************* pack operator *********************/
2541
2542 static bool image_pack_test(bContext *C, wmOperator *op)
2543 {
2544   Image *ima = CTX_data_edit_image(C);
2545
2546   if (!ima) {
2547     return 0;
2548   }
2549
2550   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2551     BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
2552     return 0;
2553   }
2554
2555   return 1;
2556 }
2557
2558 static int image_pack_exec(bContext *C, wmOperator *op)
2559 {
2560   struct Main *bmain = CTX_data_main(C);
2561   Image *ima = CTX_data_edit_image(C);
2562
2563   if (!image_pack_test(C, op)) {
2564     return OPERATOR_CANCELLED;
2565   }
2566
2567   if (BKE_image_is_dirty(ima)) {
2568     BKE_image_memorypack(ima);
2569   }
2570   else {
2571     BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
2572   }
2573
2574   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2575
2576   return OPERATOR_FINISHED;
2577 }
2578
2579 void IMAGE_OT_pack(wmOperatorType *ot)
2580 {
2581   /* identifiers */
2582   ot->name = "Pack Image";
2583   ot->description = "Pack an image as embedded data into the .blend file";
2584   ot->idname = "IMAGE_OT_pack";
2585
2586   /* api callbacks */
2587   ot->exec = image_pack_exec;
2588
2589   /* flags */
2590   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2591 }
2592
2593 /********************* unpack operator *********************/
2594
2595 static int image_unpack_exec(bContext *C, wmOperator *op)
2596 {
2597   Image *ima = CTX_data_edit_image(C);
2598   int method = RNA_enum_get(op->ptr, "method");
2599
2600   /* find the suppplied image by name */
2601   if (RNA_struct_property_is_set(op->ptr, "id")) {
2602     char imaname[MAX_ID_NAME - 2];
2603     RNA_string_get(op->ptr, "id", imaname);
2604     ima = BLI_findstring(&CTX_data_main(C)->images, imaname, offsetof(ID, name) + 2);
2605     if (!ima) {
2606       ima = CTX_data_edit_image(C);
2607     }
2608   }
2609
2610   if (!ima || !BKE_image_has_packedfile(ima)) {
2611     return OPERATOR_CANCELLED;
2612   }
2613
2614   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2615     BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2616     return OPERATOR_CANCELLED;
2617   }
2618
2619   if (G.fileflags & G_FILE_AUTOPACK) {
2620     BKE_report(op->reports,
2621                RPT_WARNING,
2622                "AutoPack is enabled, so image will be packed again on file save");
2623   }
2624
2625   /* XXX unpackImage frees image buffers */
2626   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2627
2628   unpackImage(CTX_data_main(C), op->reports, ima, method);
2629
2630   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2631
2632   return OPERATOR_FINISHED;
2633 }
2634
2635 static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2636 {
2637   Image *ima = CTX_data_edit_image(C);
2638
2639   if (RNA_struct_property_is_set(op->ptr, "id")) {
2640     return image_unpack_exec(C, op);
2641   }
2642
2643   if (!ima || !BKE_image_has_packedfile(ima)) {
2644     return OPERATOR_CANCELLED;
2645   }
2646
2647   if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2648     BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2649     return OPERATOR_CANCELLED;
2650   }
2651
2652   if (G.fileflags & G_FILE_AUTOPACK) {
2653     BKE_report(op->reports,
2654                RPT_WARNING,
2655                "AutoPack is enabled, so image will be packed again on file save");
2656   }
2657
2658   unpack_menu(C,
2659               "IMAGE_OT_unpack",
2660               ima->id.name + 2,
2661               ima->name,
2662               "textures",
2663               BKE_image_has_packedfile(ima) ?
2664                   ((ImagePackedFile *)ima->packedfiles.first)->packedfile :
2665                   NULL);
2666
2667   return OPERATOR_FINISHED;
2668 }
2669
2670 void IMAGE_OT_unpack(wmOperatorType *ot)
2671 {
2672   /* identifiers */
2673   ot->name = "Unpack Image";
2674   ot->description = "Save an image packed in the .blend file to disk";
2675   ot->idname = "IMAGE_OT_unpack";
2676
2677   /* api callbacks */
2678   ot->exec = image_unpack_exec;
2679   ot->invoke = image_unpack_invoke;
2680
2681   /* flags */
2682   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2683
2684   /* properties */
2685   RNA_def_enum(
2686       ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
2687   /* XXX, weak!, will fail with library, name collisions */
2688   RNA_def_string(
2689       ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
2690 }
2691
2692 /******************** sample image operator ********************/
2693
2694 typedef struct ImageSampleInfo {
2695   ARegionType *art;
2696   void *draw_handle;
2697   int x, y;
2698   int channels;
2699
2700   int width, height;
2701   int sample_size;
2702
2703   unsigned char col[4];
2704   float colf[4];
2705   float linearcol[4];
2706   int z;
2707   float zf;
2708
2709   unsigned char *colp;
2710   const float *colfp;
2711   int *zp;
2712   float *zfp;
2713
2714   bool draw;
2715   bool color_manage;
2716   int use_default_view;
2717 } ImageSampleInfo;
2718
2719 static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
2720 {
2721   ImageSampleInfo *info = arg_info;
2722   if (!info->draw) {
2723     return;
2724   }
2725
2726   Scene *scene = CTX_data_scene(C);
2727   ED_image_draw_info(scene,
2728                      ar,
2729                      info->color_manage,
2730                      info->use_default_view,
2731                      info->channels,
2732                      info->x,
2733                      info->y,
2734                      info->colp,
2735                      info->colfp,
2736                      info->linearcol,
2737                      info->zp,
2738                      info->zfp);
2739
2740   if (info->sample_size > 1) {
2741     const wmWindow *win = CTX_wm_window(C);
2742     const wmEvent *event = win->eventstate;
2743
2744     SpaceImage *sima = CTX_wm_space_image(C);
2745     GPUVertFormat *format = immVertexFormat();
2746     uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2747
2748     const float color[3] = {1, 1, 1};
2749     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
2750     immUniformColor3fv(color);
2751
2752     /* TODO(campbell): lock to pixels. */
2753     rctf sample_rect_fl;
2754     BLI_rctf_init_pt_radius(&sample_rect_fl,
2755                             (float[2]){event->x - ar->winrct.xmin, event->y - ar->winrct.ymin},
2756                             (float)(info->sample_size / 2.0f) * sima->zoom);
2757
2758     glEnable(GL_COLOR_LOGIC_OP);
2759     glLogicOp(GL_XOR);
2760     imm_draw_box_wire_2d(pos,
2761                          (float)sample_rect_fl.xmin,
2762                          (float)sample_rect_fl.ymin,
2763                          (float)sample_rect_fl.xmax,
2764                          (float)sample_rect_fl.ymax);
2765     glDisable(GL_COLOR_LOGIC_OP);
2766
2767     immUnbindProgram();
2768   }
2769 }
2770
2771 /* Returns color in linear space, matching ED_space_node_color_sample(). */
2772 bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
2773 {
2774   void *lock;
2775   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2776   float fx, fy;
2777   bool ret = false;
2778
2779   if (ibuf == NULL) {
2780     ED_space_image_release_buffer(sima, ibuf, lock);
2781     return false;
2782   }
2783
2784   UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
2785
2786   if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2787     const float *fp;
2788     unsigned char *cp;
2789     int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2790
2791     CLAMP(x, 0, ibuf->x - 1);
2792     CLAMP(y, 0, ibuf->y - 1);
2793
2794     if (ibuf->rect_float) {
2795       fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
2796       copy_v3_v3(r_col, fp);
2797       ret = true;
2798     }
2799     else if (ibuf->rect) {
2800       cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
2801       rgb_uchar_to_float(r_col, cp);
2802       IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
2803       ret = true;
2804     }
2805   }
2806
2807   ED_space_image_release_buffer(sima, ibuf, lock);
2808   return ret;
2809 }
2810
2811 /* -------------------------------------------------------------------- */
2812 /** \name Image Pixel Sample
2813  * \{ */
2814
2815 static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
2816                                            const int coord[2],
2817                                            uchar r_col[4],
2818                                            float r_col_linear[4])
2819 {
2820   const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
2821   copy_v4_v4_uchar(r_col, cp);
2822   rgba_uchar_to_float(r_col_linear, r_col);
2823   IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
2824 }
2825
2826 static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
2827 {
2828   const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
2829   copy_v4_v4(r_col, cp);
2830 }
2831
2832 /** \} */
2833
2834 /* -------------------------------------------------------------------- */
2835 /** \name Image Pixel Region Sample
2836  * \{ */
2837
2838 static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
2839                                           const rcti *rect,
2840                                           uchar r_col[4],
2841                                           float r_col_linear[4])
2842 {
2843   uint col_accum_ub[4] = {0, 0, 0, 0};
2844   zero_v4(r_col_linear);
2845   int col_tot = 0;
2846   int coord[2];
2847   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
2848     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
2849       float col_temp_fl[4];
2850       uchar col_temp_ub[4];
2851       image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
2852       add_v4_v4(r_col_linear, col_temp_fl);
2853       col_accum_ub[0] += (uint)col_temp_ub[0];
2854       col_accum_ub[1] += (uint)col_temp_ub[1];
2855       col_accum_ub[2] += (uint)col_temp_ub[2];
2856       col_accum_ub[3] += (uint)col_temp_ub[3];
2857       col_tot += 1;
2858     }
2859   }
2860   mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
2861
2862   r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
2863   r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
2864   r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
2865   r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
2866 }
2867
2868 static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
2869 {
2870   zero_v4(r_col);
2871   int col_tot = 0;
2872   int coord[2];
2873   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
2874     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
2875       float col_temp_fl[4];
2876       image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
2877       add_v4_v4(r_col, col_temp_fl);
2878       col_tot += 1;
2879     }
2880   }
2881   mul_v4_fl(r_col, 1.0 / (float)col_tot);
2882 }
2883
2884 /** \} */
2885
2886 static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
2887 {
2888   SpaceImage *sima = CTX_wm_space_image(C);
2889   ARegion *ar = CTX_wm_region(C);
2890   void *lock;
2891   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2892   ImageSampleInfo *info = op->customdata;
2893   float fx, fy;
2894   Scene *scene = CTX_data_scene(C);
2895   CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
2896
2897   if (ibuf == NULL) {
2898     ED_space_image_release_buffer(sima, ibuf, lock);
2899     info->draw = false;
2900     return;
2901   }
2902
2903   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
2904
2905   if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2906     int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2907     Image *image = ED_space_image(sima);
2908
2909     CLAMP(x, 0, ibuf->x - 1);
2910     CLAMP(y, 0, ibuf->y - 1);
2911
2912     info->width = ibuf->x;
2913     info->height = ibuf->y;
2914     info->x = x;
2915     info->y = y;
2916
2917     info->draw = true;
2918     info->channels = ibuf->channels;
2919
2920     info->colp = NULL;
2921     info->colfp = NULL;
2922     info->zp = NULL;
2923     info->zfp = NULL;
2924
2925     info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
2926
2927     rcti sample_rect;
2928     sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
2929     sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
2930     sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
2931     sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
2932
2933     if (ibuf->rect) {
2934       image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
2935       rgba_uchar_to_float(info->colf, info->col);
2936
2937       info->colp = info->col;
2938       info->colfp = info->colf;
2939       info->color_manage = true;
2940     }
2941     if (ibuf->rect_float) {
2942       image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
2943
2944       if (ibuf->channels == 4) {
2945         /* pass */
2946       }
2947       else if (ibuf->channels == 3) {
2948         info->colf[3] = 1.0f;
2949       }
2950       else {
2951         info->colf[1] = info->colf[0];
2952         info->colf[2] = info->colf[0];
2953         info->colf[3] = 1.0f;
2954       }
2955       info->colfp = info->colf;
2956
2957       copy_v4_v4(info->linearcol, info->colf);
2958
2959       info->color_manage = true;
2960     }
2961
2962     if (ibuf->zbuf) {
2963       /* TODO, blend depth (not urgent). */
2964       info->z = ibuf->zbuf[y * ibuf->x + x];
2965       info->zp = &info->z;
2966       if (ibuf->zbuf == (int *)ibuf->rect) {
2967         info->colp = NULL;
2968       }
2969     }
2970     if (ibuf->zbuf_float) {
2971       /* TODO, blend depth (not urgent). */
2972       info->zf = ibuf->zbuf_float[y * ibuf->x + x];
2973       info->zfp = &info->zf;
2974       if (ibuf->zbuf_float == ibuf->rect_float) {
2975         info->colfp = NULL;
2976       }
2977     }
2978
2979     if (curve_mapping && ibuf->channels == 4) {
2980       /* we reuse this callback for set curves point operators */
2981       if (RNA_struct_find_property(op->ptr, "point")) {
2982         int point = RNA_enum_get(op->ptr, "point");
2983
2984         if (point == 1) {
2985           curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
2986         }
2987         else if (point == 0) {
2988           curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
2989         }
2990         WM_event_add_notifier(C, NC_WINDOW, NULL);
2991       }
2992     }
2993
2994     // XXX node curve integration ..
2995 #if 0
2996     {
2997       ScrArea *sa, *cur = curarea;
2998
2999       node_curvemap_sample(fp); /* sends global to node editor */
3000       for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
3001         if (sa->spacetype == SPACE_NODE) {
3002           areawinset(sa->win);
3003           scrarea_do_windraw(sa);
3004         }
3005       }
3006       node_curvemap_sample(NULL); /* clears global in node editor */
3007       curarea = cur;
3008     }
3009 #endif
3010   }
3011   else {
3012     info->draw = 0;
3013   }
3014
3015   ED_space_image_release_buffer(sima, ibuf, lock);
3016   ED_area_tag_redraw(CTX_wm_area(C));
3017 }
3018
3019 static void image_sample_exit(bContext *C, wmOperator *op)
3020 {
3021   ImageSampleInfo *info = op->customdata;
3022
3023   ED_region_draw_cb_exit(info->art, info->draw_handle);
3024   ED_area_tag_redraw(CTX_wm_area(C));
3025   MEM_freeN(info);
3026 }
3027
3028 static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3029 {
3030   SpaceImage *sima = CTX_wm_space_image(C);
3031   ARegion *ar = CTX_wm_region(C);
3032   ImageSampleInfo *info;
3033
3034   if (ar->regiontype == RGN_TYPE_WINDOW) {
3035     if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
3036       return OPERATOR_PASS_THROUGH;
3037     }
3038   }
3039
3040   if (!ED_space_image_has_buffer(sima)) {
3041     return OPERATOR_CANCELLED;
3042   }
3043
3044   info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
3045
3046   info->art = ar->type;
3047   info->draw_handle = ED_region_draw_cb_activate(
3048       ar->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
3049   info->sample_size = RNA_int_get(op->ptr, "size");
3050   op->customdata = info;
3051
3052   image_sample_apply(C, op, event);
3053
3054   WM_event_add_modal_handler(C, op);
3055
3056   return OPERATOR_RUNNING_MODAL;
3057 }
3058
3059 static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
3060 {
3061   switch (event->type) {
3062     case LEFTMOUSE:
3063     case RIGHTMOUSE:  // XXX hardcoded
3064       if (event->val == KM_RELEASE) {
3065         image_sample_exit(C, op);
3066         return OPERATOR_CANCELLED;
3067       }
3068       break;
3069     case MOUSEMOVE:
3070       image_sample_apply(C, op, event);
3071       break;
3072   }
3073
3074   return OPERATOR_RUNNING_MODAL;
3075 }
3076
3077 static void image_sample_cancel(bContext *C, wmOperator *op)
3078 {
3079   image_sample_exit(C, op);
3080 }
3081
3082 void IMAGE_OT_sample(wmOperatorType *ot)
3083 {
3084   /* identifiers */
3085   ot->name = "Sample Color";
3086   ot->idname = "IMAGE_OT_sample";
3087   ot->description = "Use mouse to sample a color in current image";
3088
3089   /* api callbacks */
3090   ot->invoke = image_sample_invoke;
3091   ot->modal = image_sample_modal;
3092   ot->cancel = image_sample_cancel;
3093   ot->poll = image_sample_poll;
3094
3095   /* flags */
3096   ot->flag = OPTYPE_BLOCKING;
3097
3098   PropertyRNA *prop;
3099   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3100   RNA_def_property_subtype(prop, PROP_PIXEL);
3101   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3102 }
3103
3104 /******************** sample line operator ********************/
3105 static int image_sample_line_exec(bContext *C, wmOperator *op)
3106 {
3107   SpaceImage *sima = CTX_wm_space_image(C);
3108   ARegion *ar = CTX_wm_region(C);
3109   Scene *scene = CTX_data_scene(C);
3110
3111   int x_start = RNA_int_get(op->ptr, "xstart");
3112   int y_start = RNA_int_get(op->ptr, "ystart");
3113   int x_end = RNA_int_get(op->ptr, "xend");
3114   int y_end = RNA_int_get(op->ptr, "yend");
3115
3116   void *lock;
3117   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
3118   Histogram *hist = &sima->sample_line_hist;
3119
3120   float x1f, y1f, x2f, y2f;
3121
3122   if (ibuf == NULL) {
3123     ED_space_image_release_buffer(sima, ibuf, lock);
3124     return OPERATOR_CANCELLED;
3125   }
3126   /* hmmmm */
3127   if (ibuf->channels < 3) {
3128     ED_space_image_release_buffer(sima, ibuf, lock);
3129     return OPERATOR_CANCELLED;
3130   }
3131
3132   UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
3133   UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
3134
3135   hist->co[0][0] = x1f;
3136   hist->co[0][1] = y1f;
3137   hist->co[1][0] = x2f;
3138   hist->co[1][1] = y2f;
3139
3140   /* enable line drawing */
3141   hist->flag |= HISTO_FLAG_SAMPLELINE;
3142
3143   BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
3144
3145   /* reset y zoom */
3146   hist->ymax = 1.0f;
3147
3148   ED_space_image_release_buffer(sima, ibuf, lock);
3149
3150   ED_area_tag_redraw(CTX_wm_area(C));
3151
3152   return OPERATOR_FINISHED;
3153 }
3154
3155 static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3156 {
3157   SpaceImage *sima = CTX_wm_space_image(C);
3158
3159   Histogram *hist = &sima->sample_line_hist;
3160   hist->flag &= ~HISTO_FLAG_SAMPLELINE;
3161
3162   if (!ED_space_image_has_buffer(sima)) {
3163     return OPERATOR_CANCELLED;
3164   }
3165
3166   return WM_gesture_straightline_invoke(C, op, event);
3167 }
3168
3169 void IMAGE_OT_sample_line(wmOperatorType *ot)
3170 {
3171   /* identifiers */
3172   ot->name = "Sample Line";
3173   ot->idname = "IMAGE_OT_sample_line";
3174   ot->description = "Sample a line and show it in Scope panels";
3175
3176   /* api callbacks */
3177   ot->invoke = image_sample_line_invoke;
3178   ot->modal = WM_gesture_straightline_modal;
3179   ot->exec = image_sample_line_exec;
3180   ot->poll = space_image_main_region_poll;
3181   ot->cancel = WM_gesture_straightline_cancel;
3182
3183   /* flags */
3184   ot->flag = 0; /* no undo/register since this operates on the space */
3185
3186   WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
3187 }
3188
3189 /******************** set curve point operator ********************/
3190
3191 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
3192 {
3193   static const EnumPropertyItem point_items[] = {
3194       {0, "BLACK_POINT", 0, "Black Point", ""},
3195       {1, "WHITE_POINT", 0, "White Point", ""},
3196       {0, NULL, 0, NULL, NULL},
3197   };
3198
3199   /* identifiers */
3200   ot->name = "Set Curves Point";
3201   ot->idname = "IMAGE_OT_curves_point_set";
3202   ot->description = "Set black point or white point for curves";
3203
3204   /* flags */
3205   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3206
3207   /* api callbacks */
3208   ot->invoke = image_sample_invoke;
3209   ot->modal = image_sample_modal;
3210   ot->cancel = image_sample_cancel;
3211   ot->poll = space_image_main_area_not_uv_brush_poll;
3212
3213   /* properties */
3214   RNA_def_enum(
3215       ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3216
3217   PropertyRNA *prop;
3218   prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3219   RNA_def_property_subtype(prop, PROP_PIXEL);
3220   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3221 }
3222
3223 #if 0 /* Not ported to 2.5x yet */
3224 /******************** record composite operator *********************/
3225
3226 typedef struct RecordCompositeData {
3227   wmTimer *timer;
3228   int old_cfra;
3229   int sfra, efra;
3230 } RecordCompositeData;
3231
3232 static int image_record_composite_apply(bContext *C, wmOperator *op)
3233 {
3234   SpaceImage *sima = CTX_wm_space_image(C);
3235   RecordCompositeData *rcd = op->customdata;
3236   Scene *scene = CTX_data_scene(C);
3237   ImBuf *ibuf;
3238
3239   WM_cursor_time(CTX_wm_window(C), scene->r.cfra);
3240
3241   // XXX scene->nodetree->test_break = BKE_blender_test_break;
3242   // XXX scene->nodetree->test_break = NULL;
3243
3244   BKE_image_all_free_anim_ibufs(scene->r.cfra);
3245   ntreeCompositExecTree(scene->nodetree,
3246                         &scene->r,
3247                         0,
3248                         scene->r.cfra != rcd->old_cfra,
3249                         &scene->view_settings,
3250                         &scene->display_settings); /* 1 is no previews */
3251
3252   ED_area_tag_redraw(CTX_wm_area(C));
3253
3254   ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, NULL);
3255   /* save memory in flipbooks */
3256   if (ibuf)
3257     imb_freerectfloatImBuf(ibuf);
3258
3259   BKE_image_release_ibuf(sima->image, ibuf, NULL);
3260
3261   scene->r.cfra++;
3262
3263   return (scene->r.cfra <= rcd->efra);
3264 }
3265
3266 static int image_record_composite_init(bContext *C, wmOperator *op)
3267 {
3268   SpaceImage *sima = CTX_wm_space_image(C);
3269   Scene *scene = CTX_data_scene(C);
3270   RecordCompositeData *rcd;
3271
3272   if (sima->iuser.frames < 2)
3273     return 0;
3274   if (scene->nodetree == NULL)
3275     return 0;
3276
3277   op->customdata = rcd = MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData");
3278
3279   rcd->old_cfra = scene->r.cfra;
3280   rcd->sfra = sima->iuser.sfra;
3281   rcd->efra = sima->iuser.sfra + sima->iuser.frames - 1;
3282   scene->r.cfra = rcd->sfra;
3283
3284   return 1;
3285 }
3286
3287 static void image_record_composite_exit(bContext *C, wmOperator *op)
3288 {
3289   Scene *scene = CTX_data_scene(C);
3290   SpaceImage *sima = CTX_wm_space_image(C);
3291   RecordCompositeData *rcd = op->customdata;
3292
3293   scene->r.cfra = rcd->old_cfra;
3294
3295   WM_cursor_modal_restore(CTX_wm_window(C));
3296
3297   if (rcd->timer)
3298     WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer);
3299
3300   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
3301
3302   // XXX play_anim(0);
3303   // XXX allqueue(REDRAWNODE, 1);
3304
3305   MEM_freeN(rcd);
3306 }
3307
3308 static int image_record_composite_exec(bContext *C, wmOperator *op)
3309 {
3310   if (!image_record_composite_init(C, op))
3311     return OPERATOR_CANCELLED;
3312
3313   while (image_record_composite_apply(C, op)) {
3314   }
3315
3316   image_record_composite_exit(C, op);
3317
3318   return OPERATOR_FINISHED;
3319 }
3320
3321 static int image_record_composite_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
3322 {
3323   RecordCompositeData *rcd;
3324
3325   if (!image_record_composite_init(C, op))
3326     return OPERATOR_CANCELLED;
3327
3328   rcd = op->customdata;
3329   rcd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.0f);
3330   WM_event_add_modal_handler(C, op);
3331
3332   if (!image_record_composite_apply(C, op))
3333     return OPERATOR_FINISHED;
3334
3335   return OPERATOR_RUNNING_MODAL;
3336 }
3337
3338 static int image_record_composite_modal(bContext *C, wmOperator *op, const wmEvent *event)
3339 {
3340   RecordCompositeData *rcd = op->customdata;
3341
3342   switch (event->type) {
3343     case TIMER:
3344       if (rcd->timer == event->customdata) {
3345         if (!image_record_composite_apply(C, op)) {
3346           image_record_composite_exit(C, op);
3347           return OPERATOR_FINISHED;
3348         }
3349       }
3350       break;
3351     case ESCKEY:
3352       image_record_composite_exit(C, op);
3353       return OPERATOR_FINISHED;
3354   }
3355
3356   return OPERATOR_RUNNING_MODAL;
3357 }
3358
3359 static void image_record_composite_cancel(bContext *C, wmOperator *op)
3360 {
3361   image_record_composite_exit(C, op);
3362   return OPERATOR_CANCELLED;
3363 }
3364
3365 void IMAGE_OT_record_composite(wmOperatorType *ot)
3366 {
3367   /* identifiers */
3368   ot->name = "Record Composite";
3369   ot->idname = "IMAGE_OT_record_composite";
3370
3371   /* api callbacks */
3372   ot->exec = image_record_composite_exec;
3373   ot->invoke = image_record_composite_invoke;
3374   ot->modal = image_record_composite_modal;
3375   ot->cancel = image_record_composite_cancel;
3376   ot->poll = space_image_buffer_exists_poll;
3377 }
3378
3379 #endif
3380
3381 /********************* cycle render slot operator *********************/
3382
3383 static bool image_cycle_render_slot_poll(bContext *C)
3384 {
3385   Image *ima = CTX_data_edit_image(C);
3386
3387   return (ima && ima->type == IMA_TYPE_R_RESULT);
3388 }
3389
3390 static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
3391 {
3392   Image *ima = CTX_data_edit_image(C);
3393   const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
3394
3395   if (!ED_image_slot_cycle(ima, direction)) {
3396     return OPERATOR_CANCELLED;
3397   }
3398
3399   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3400
3401   /* no undo push for browsing existing */
3402   RenderSlot *slot = BKE_image_get_renderslot(ima, ima->render_slot);
3403   if ((slot && slot->render) || ima->render_slot == ima->last_render_slot) {
3404     return OPERATOR_CANCELLED;
3405   }
3406
3407   return OPERATOR_FINISHED;
3408 }
3409
3410 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
3411 {
3412   /* identifiers */
3413   ot->name = "Cycle Render Slot";
3414   ot->idname = "IMAGE_OT_cycle_render_slot";
3415   ot->description = "Cycle through all non-void render slots";
3416
3417   /* api callbacks */
3418   ot->exec = image_cycle_render_slot_exec;
3419   ot->poll = image_cycle_render_slot_poll;
3420
3421   /* flags */
3422   ot->flag = OPTYPE_REGISTER;
3423
3424   RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
3425 }
3426
3427 /********************* clear render slot operator *********************/
3428
3429 static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3430 {
3431   SpaceImage *sima = CTX_wm_space_image(C);
3432   Image *ima = CTX_data_edit_image(C);
3433
3434   if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
3435     return OPERATOR_CANCELLED;
3436   }
3437
3438   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3439
3440   return OPERATOR_FINISHED;
3441 }
3442
3443 void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
3444 {
3445   /* identifiers */
3446   ot->name = "Clear Render Slot";
3447   ot->idname = "IMAGE_OT_clear_render_slot";
3448   ot->description = "Clear the currently selected render slot";
3449
3450   /* api callbacks */
3451   ot->exec = image_clear_render_slot_exec;
3452   ot->poll = image_cycle_render_slot_poll;
3453
3454   /* flags */
3455   ot->flag = OPTYPE_REGISTER;
3456 }
3457
3458 /********************* add render slot operator *********************/
3459
3460 static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3461 {
3462   Image *ima = CTX_data_edit_image(C);
3463
3464   RenderSlot *slot = BKE_image_add_renderslot(ima, NULL);
3465   ima->render_slot = BLI_findindex(&ima->renderslots, slot);
3466
3467   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3468
3469   return OPERATOR_FINISHED;
3470 }
3471
3472 void IMAGE_OT_add_render_slot(wmOperatorType *ot)
3473 {
3474   /* identifiers */
3475   ot->name = "Add Render Slot";
3476   ot->idname = "IMAGE_OT_add_render_slot";
3477   ot->description = "Add a new render slot";
3478
3479   /* api callbacks */
3480   ot->exec = image_add_render_slot_exec;
3481   ot->poll = image_cycle_render_slot_poll;
3482
3483   /* flags */
3484   ot->flag = OPTYPE_REGISTER;
3485 }
3486
3487 /********************* remove render slot operator *********************/
3488
3489 static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
3490 {
3491   SpaceImage *sima = CTX_wm_space_image(C);
3492   Image *ima = CTX_data_edit_image(C);
3493
3494   if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
3495     return OPERATOR_CANCELLED;
3496   }
3497
3498   WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
3499
3500   return OPERATOR_FINISHED;
3501 }
3502
3503 void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
3504 {
3505   /* identifiers */
3506   ot->name = "Remove Render Slot";
3507   ot->idname = "IMAGE_OT_remove_render_slot";
3508   ot->description = "Remove the current render slot";
3509
3510   /* api callbacks */
3511   ot->exec = image_remove_render_slot_exec;
3512   ot->poll = image_cycle_render_slot_poll;
3513
3514   /* flags */
3515   ot->flag = OPTYPE_REGISTER;
3516 }
3517
3518 /********************** change frame operator *********************/
3519
3520 static bool change_frame_poll(bContext *C)
3521 {
3522   /* prevent changes during render */
3523   if (G.is_rendering) {
3524     return 0;
3525   }
3526
3527   return space_image_main_region_poll(C);
3528 }
3529
3530 static void change_frame_apply(bContext *C, wmOperator *op)
3531 {
3532   Scene *scene = CTX_data_scene(C);
3533
3534   /* set the new frame number */
3535   CFRA = RNA_int_get(op->ptr, "frame");
3536   FRAMENUMBER_MIN_CLAMP(CFRA);
3537   SUBFRA = 0.0f;
3538
3539   /* do updates */
3540   BKE_sound_seek_scene(CTX_data_main(C), scene);
3541   WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
3542 }
3543
3544 static int change_frame_exec(bContext *C, wmOperator *op)
3545 {
3546   change_frame_apply(C, op);
3547
3548   return OPERATOR_FINISHED;
3549 }
3550
3551 static int frame_from_event(bContext *C, const wmEvent *event)
3552 {
3553   ARegion *ar = CTX_wm_region(C);
3554   Scene *scene = CTX_data_scene(C);
3555   int framenr = 0;
3556
3557   if (ar->regiontype == RGN_TYPE_WINDOW) {
3558     float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
3559
3560     framenr = sfra + event->mval[0] / framelen;
3561   }
3562   else {
3563     float viewx, viewy;
3564
3565     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
3566
3567     framenr = round_fl_to_int(viewx);
3568   }
3569
3570   return framenr;
3571 }
3572
3573 static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3574 {
3575   ARegion *ar = CTX_wm_region(C);
3576
3577   if (ar->regiontype == RGN_TYPE_WINDOW) {
3578     SpaceImage *sima = CTX_wm_space_image(C);
3579     if (event->mval[1] > 16 || !ED_space_image_show_cache(sima)) {
3580       return OPERATOR_PASS_THROUGH;
3581     }
3582   }
3583
3584   RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3585
3586   change_frame_apply(C, op);
3587
3588   /* add temp handler */
3589   WM_event_add_modal_handler(C, op);
3590
3591   return OPERATOR_RUNNING_MODAL;
3592 }
3593
3594 static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
3595 {
3596   switch (event->type) {
3597     case ESCKEY:
3598       return OPERATOR_FINISHED;
3599
3600     case MOUSEMOVE:
3601       RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3602       change_frame_apply(C, op);
3603       break;
3604
3605     case LEFTMOUSE:
3606     case RIGHTMOUSE:
3607       if (event->val == KM_RELEASE) {
3608         return OPERATOR_FINISHED;
3609       }
3610       break;
3611   }
3612
3613   return OPERATOR_RUNNING_MODAL;
3614 }
3615
3616 void IMAGE_OT_change_frame(wmOperatorType *ot)
3617 {
3618   /* identifiers */
3619   ot->name = "Change Frame";
3620   ot->idname = "IMAGE_OT_change_frame";
3621   ot->description = "Interactively change the current frame number";
3622
3623   /* api callbacks */
3624   ot->exec = change_frame_exec;
3625   ot->invoke = change_frame_invoke;
3626   ot->modal = change_frame_modal;
3627   ot->poll = change_frame_poll;
3628
3629   /* flags */
3630   ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
3631
3632   /* rna */
3633   RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
3634 }
3635
3636 /* Reload cached render results... */
3637 /* goes over all scenes, reads render layers */
3638 static int image_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
3639 {
3640   Main *bmain = CTX_data_main(C);
3641   Scene *scene = CTX_data_scene(C);
3642   SpaceImage *sima = CTX_wm_space_image(C);
3643   Image *ima;
3644
3645   ima = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
3646   if (sima->image == NULL) {
3647     ED_space_image_set(bmain, sima, NULL, ima, false);
3648   }
3649
3650   RE_ReadRenderResult(scene, scene);
3651
3652   WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
3653   return OPERATOR_FINISHED;
3654 }
3655
3656 void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
3657 {
3658   ot->name = "Open Cached Render";
3659   ot->idname = "IMAGE_OT_read_viewlayers";
3660   ot->description = "Read all the current scene's view layers from cache, as needed";
3661
3662   ot->poll = space_image_main_region_poll;
3663   ot->exec = image_read_viewlayers_exec;
3664
3665   /* flags */
3666   ot->flag = 0;
3667 }
3668
3669 /* ********************* Render border operator ****************** */
3670
3671 static int render_border_exec(bContext *C, wmOperator *op)
3672 {
3673   ARegion *ar = CTX_wm_region(C);
3674   Scene *scene = CTX_data_scene(C);
3675   Render *re = RE_GetSceneRender(scene);
3676   RenderData *rd;
3677   rctf border;
3678
3679   if (re == NULL) {
3680     /* Shouldn't happen, but better be safe close to the release. */
3681     return OPERATOR_CANCELLED;
3682   }
3683
3684   rd = RE_engine_get_render_data(re);
3685   if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
3686     BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render");
3687     return OPERATOR_CANCELLED;
3688   }
3689
3690   /* get rectangle from operator */
3691   WM_operator_properties_border_to_rctf(op, &border);
3692   UI_view2d_region_to_view_rctf(&ar->v2d, &border, &border);
3693
3694   /* actually set border */
3695   CLAMP(border.xmin, 0.0f, 1.0f);
3696   CLAMP(border.ymin, 0.0f, 1.0f);
3697   CLAMP(border.xmax, 0.0f, 1.0f);
3698   CLAMP(border.ymax, 0.0f, 1.0f);
3699   scene->r.border = border;
3700
3701   /* drawing a border surrounding the entire camera view switches off border rendering
3702    * or the border covers no pixels */
3703   if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
3704       (border.xmin == border.xmax || border.ymin == border.ymax)) {
3705     scene->r.mode &= ~R_BORDER;
3706   }
3707   else {
3708     scene->r.mode |= R_BORDER;
3709   }
3710
3711   DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
3712   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3713
3714   return OPERATOR_FINISHED;
3715 }
3716
3717 void IMAGE_OT_render_border(wmOperatorType *ot)
3718 {
3719   /* identifiers */
3720   ot->name = "Render Region";
3721   ot->description = "Set the boundaries of the render region and enable render region";
3722   ot->idname = "IMAGE_OT_render_border";
3723
3724   /* api callbacks */
3725   ot->invoke = WM_gesture_box_invoke;
3726   ot->exec = render_border_exec;
3727   ot->modal = WM_gesture_box_modal;
3728   ot->cancel = WM_gesture_box_cancel;
3729   ot->poll = image_cycle_render_slot_poll;
3730
3731   /* flags */
3732   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3733
3734   /* rna */
3735   WM_operator_properties_border(ot);
3736 }
3737
3738 /* ********************* Clear render border operator ****************** */
3739
3740 static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
3741 {
3742   Scene *scene = CTX_data_scene(C);
3743   scene->r.mode &= ~R_BORDER;
3744   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
3745   BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
3746   return OPERATOR_FINISHED;
3747 }
3748
3749 void IMAGE_OT_clear_render_border(wmOperatorType *ot)
3750 {
3751   /* identifiers */
3752   ot->name = "Clear Render Region";
3753   ot->description = "Clear the boundaries of the render region and disable render region";
3754   ot->idname = "IMAGE_OT_clear_render_border";
3755
3756   /* api callbacks */
3757   ot->exec = clear_render_border_exec;
3758   ot->poll = image_cycle_render_slot_poll;
3759
3760   /* flags */
3761   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3762 }