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