Multi-View and Stereo 3D
[blender-staging.git] / source / blender / editors / space_image / image_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2009, Xavier Thomas
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_image/image_ops.c
27  *  \ingroup spimage
28  */
29
30
31 #include <stddef.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #ifndef WIN32
37 #  include <unistd.h>
38 #else
39 #  include <io.h>
40 #endif
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_math.h"
45 #include "BLI_blenlib.h"
46 #include "BLI_utildefines.h"
47 #include "BLI_string_utf8.h"
48
49 #include "BLF_translation.h"
50
51 #include "DNA_object_types.h"
52 #include "DNA_node_types.h"
53 #include "DNA_packedFile_types.h"
54 #include "DNA_scene_types.h"
55
56 #include "BKE_colortools.h"
57 #include "BKE_context.h"
58 #include "BKE_depsgraph.h"
59 #include "BKE_DerivedMesh.h"
60 #include "BKE_icons.h"
61 #include "BKE_image.h"
62 #include "BKE_global.h"
63 #include "BKE_library.h"
64 #include "BKE_main.h"
65 #include "BKE_packedFile.h"
66 #include "BKE_paint.h"
67 #include "BKE_report.h"
68 #include "BKE_screen.h"
69 #include "BKE_sound.h"
70 #include "BKE_scene.h"
71
72 #include "GPU_draw.h"
73 #include "GPU_buffers.h"
74
75 #include "IMB_colormanagement.h"
76 #include "IMB_imbuf.h"
77 #include "IMB_imbuf_types.h"
78 #include "IMB_moviecache.h"
79 #include "intern/openexr/openexr_multi.h"
80
81 #include "RE_pipeline.h"
82
83 #include "RNA_access.h"
84 #include "RNA_define.h"
85 #include "RNA_enum_types.h"
86
87 #include "ED_image.h"
88 #include "ED_paint.h"
89 #include "ED_render.h"
90 #include "ED_screen.h"
91 #include "ED_space_api.h"
92 #include "ED_uvedit.h"
93 #include "ED_util.h"
94
95 #include "UI_interface.h"
96 #include "UI_resources.h"
97 #include "UI_view2d.h"
98
99 #include "WM_api.h"
100 #include "WM_types.h"
101
102 #include "PIL_time.h"
103
104 #include "RE_engine.h"
105
106 #include "image_intern.h"
107
108 /******************** view navigation utilities *********************/
109
110 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom, const float location[2])
111 {
112         float oldzoom = sima->zoom;
113         int width, height;
114
115         sima->zoom = zoom;
116
117         if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
118                 /* check zoom limits */
119                 ED_space_image_get_size(sima, &width, &height);
120
121                 width *= sima->zoom;
122                 height *= sima->zoom;
123
124                 if ((width < 4) && (height < 4))
125                         sima->zoom = oldzoom;
126                 else if (BLI_rcti_size_x(&ar->winrct) <= sima->zoom)
127                         sima->zoom = oldzoom;
128                 else if (BLI_rcti_size_y(&ar->winrct) <= sima->zoom)
129                         sima->zoom = oldzoom;
130         }
131
132         if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) && location) {
133                 float aspx, aspy, w, h;
134
135                 ED_space_image_get_size(sima, &width, &height);
136                 ED_space_image_get_aspect(sima, &aspx, &aspy);
137
138                 w = width * aspx;
139                 h = height * aspy;
140
141                 sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
142                 sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
143         }
144 }
145
146 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac, const float location[2])
147 {
148         sima_zoom_set(sima, ar, sima->zoom * zoomfac, location);
149 }
150
151 #if 0 // currently unused
152 static int image_poll(bContext *C)
153 {
154         return (CTX_data_edit_image(C) != NULL);
155 }
156 #endif
157
158 static int space_image_buffer_exists_poll(bContext *C)
159 {
160         SpaceImage *sima = CTX_wm_space_image(C);
161         if (sima && sima->spacetype == SPACE_IMAGE)
162                 if (ED_space_image_has_buffer(sima))
163                         return 1;
164         return 0;
165 }
166
167 static int space_image_file_exists_poll(bContext *C)
168 {
169         if (space_image_buffer_exists_poll(C)) {
170                 Main *bmain = CTX_data_main(C);
171                 SpaceImage *sima = CTX_wm_space_image(C);
172                 ImBuf *ibuf;
173                 void *lock;
174                 bool ret = false;
175                 char name[FILE_MAX];
176
177                 ibuf = ED_space_image_acquire_buffer(sima, &lock);
178                 if (ibuf) {
179                         BLI_strncpy(name, ibuf->name, FILE_MAX);
180                         BLI_path_abs(name, bmain->name);
181
182                         if (BLI_exists(name) == false) {
183                                 CTX_wm_operator_poll_msg_set(C, "image file not found");
184                         }
185                         else if (!BLI_file_is_writable(name)) {
186                                 CTX_wm_operator_poll_msg_set(C, "image path can't be written to");
187                         }
188                         else {
189                                 ret = true;
190                         }
191                 }
192                 ED_space_image_release_buffer(sima, ibuf, lock);
193
194                 return ret;
195         }
196         return 0;
197 }
198
199 static int space_image_poll(bContext *C)
200 {
201         SpaceImage *sima = CTX_wm_space_image(C);
202         if (sima && sima->spacetype == SPACE_IMAGE && sima->image)
203                 return 1;
204         return 0;
205 }
206
207 int space_image_main_area_poll(bContext *C)
208 {
209         SpaceImage *sima = CTX_wm_space_image(C);
210         // XXX ARegion *ar = CTX_wm_region(C);
211
212         if (sima)
213                 return 1;  // XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW);
214         
215         return 0;
216 }
217
218 /* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode or editmode */
219 static int space_image_main_area_not_uv_brush_poll(bContext *C)
220 {
221         SpaceImage *sima = CTX_wm_space_image(C);
222         Scene *scene = CTX_data_scene(C);
223         ToolSettings *toolsettings = scene->toolsettings;
224
225         if (sima && !toolsettings->uvsculpt && !scene->obedit)
226                 return 1;
227
228         return 0;
229 }
230
231 static int image_sample_poll(bContext *C)
232 {
233         SpaceImage *sima = CTX_wm_space_image(C);
234         if (sima) {
235                 Scene *scene = CTX_data_scene(C);
236                 Object *obedit = CTX_data_edit_object(C);
237                 ToolSettings *toolsettings = scene->toolsettings;
238
239                 if (obedit) {
240                         if (ED_space_image_show_uvedit(sima, obedit) && (toolsettings->use_uv_sculpt))
241                                 return false;
242                 }
243                 else if (sima->mode != SI_MODE_VIEW) {
244                         return false;
245                 }
246
247                 return space_image_main_area_poll(C);
248         }
249         else {
250                 return false;
251         }
252 }
253 /********************** view pan operator *********************/
254
255 typedef struct ViewPanData {
256         float x, y;
257         float xof, yof;
258         int event_type;
259 } ViewPanData;
260
261 static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
262 {
263         SpaceImage *sima = CTX_wm_space_image(C);
264         ViewPanData *vpd;
265
266         op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
267         WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
268
269         vpd->x = event->x;
270         vpd->y = event->y;
271         vpd->xof = sima->xof;
272         vpd->yof = sima->yof;
273         vpd->event_type = event->type;
274
275         WM_event_add_modal_handler(C, op);
276 }
277
278 static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
279 {
280         SpaceImage *sima = CTX_wm_space_image(C);
281         ViewPanData *vpd = op->customdata;
282
283         if (cancel) {
284                 sima->xof = vpd->xof;
285                 sima->yof = vpd->yof;
286                 ED_region_tag_redraw(CTX_wm_region(C));
287         }
288
289         WM_cursor_modal_restore(CTX_wm_window(C));
290         MEM_freeN(op->customdata);
291 }
292
293 static int image_view_pan_exec(bContext *C, wmOperator *op)
294 {
295         SpaceImage *sima = CTX_wm_space_image(C);
296         float offset[2];
297
298         RNA_float_get_array(op->ptr, "offset", offset);
299         sima->xof += offset[0];
300         sima->yof += offset[1];
301
302         ED_region_tag_redraw(CTX_wm_region(C));
303
304         /* XXX notifier? */
305 #if 0
306         if (image_preview_active(curarea, NULL, NULL)) {
307                 /* recalculates new preview rect */
308                 scrarea_do_windraw(curarea);
309                 image_preview_event(2);
310         }
311 #endif
312         
313         return OPERATOR_FINISHED;
314 }
315
316 static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
317 {
318         if (event->type == MOUSEPAN) {
319                 SpaceImage *sima = CTX_wm_space_image(C);
320                 float offset[2];
321                 
322                 offset[0] = (event->prevx - event->x) / sima->zoom;
323                 offset[1] = (event->prevy - event->y) / sima->zoom;
324                 RNA_float_set_array(op->ptr, "offset", offset);
325
326                 image_view_pan_exec(C, op);
327                 return OPERATOR_FINISHED;
328         }
329         else {
330                 image_view_pan_init(C, op, event);
331                 return OPERATOR_RUNNING_MODAL;
332         }
333 }
334
335 static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
336 {
337         SpaceImage *sima = CTX_wm_space_image(C);
338         ViewPanData *vpd = op->customdata;
339         float offset[2];
340
341         switch (event->type) {
342                 case MOUSEMOVE:
343                         sima->xof = vpd->xof;
344                         sima->yof = vpd->yof;
345                         offset[0] = (vpd->x - event->x) / sima->zoom;
346                         offset[1] = (vpd->y - event->y) / sima->zoom;
347                         RNA_float_set_array(op->ptr, "offset", offset);
348                         image_view_pan_exec(C, op);
349                         break;
350                 default:
351                         if (event->type == vpd->event_type && event->val == KM_RELEASE) {
352                                 image_view_pan_exit(C, op, false);
353                                 return OPERATOR_FINISHED;
354                         }
355                         break;
356         }
357
358         return OPERATOR_RUNNING_MODAL;
359 }
360
361 static void image_view_pan_cancel(bContext *C, wmOperator *op)
362 {
363         image_view_pan_exit(C, op, true);
364 }
365
366 void IMAGE_OT_view_pan(wmOperatorType *ot)
367 {
368         /* identifiers */
369         ot->name = "View Pan";
370         ot->idname = "IMAGE_OT_view_pan";
371         ot->description = "Pan the view";
372         
373         /* api callbacks */
374         ot->exec = image_view_pan_exec;
375         ot->invoke = image_view_pan_invoke;
376         ot->modal = image_view_pan_modal;
377         ot->cancel = image_view_pan_cancel;
378         ot->poll = space_image_main_area_poll;
379
380         /* flags */
381         ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
382         
383         /* properties */
384         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
385                              "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
386 }
387
388 /********************** view zoom operator *********************/
389
390 typedef struct ViewZoomData {
391         float origx, origy;
392         float zoom;
393         int event_type;
394         float location[2];
395
396         /* needed for continuous zoom */
397         wmTimer *timer;
398         double timer_lastdraw;
399
400         /* */
401         SpaceImage *sima;
402         ARegion *ar;
403 } ViewZoomData;
404
405 static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
406 {
407         SpaceImage *sima = CTX_wm_space_image(C);
408         ARegion *ar = CTX_wm_region(C);
409         ViewZoomData *vpd;
410
411         op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
412         WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
413
414         vpd->origx = event->x;
415         vpd->origy = event->y;
416         vpd->zoom = sima->zoom;
417         vpd->event_type = event->type;
418
419         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
420
421         if (U.viewzoom == USER_ZOOM_CONT) {
422                 /* needs a timer to continue redrawing */
423                 vpd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
424                 vpd->timer_lastdraw = PIL_check_seconds_timer();
425         }
426
427         vpd->sima = sima;
428         vpd->ar = ar;
429
430         WM_event_add_modal_handler(C, op);
431 }
432
433 static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
434 {
435         SpaceImage *sima = CTX_wm_space_image(C);
436         ViewZoomData *vpd = op->customdata;
437
438         if (cancel) {
439                 sima->zoom = vpd->zoom;
440                 ED_region_tag_redraw(CTX_wm_region(C));
441         }
442
443         if (vpd->timer)
444                 WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
445
446         WM_cursor_modal_restore(CTX_wm_window(C));
447         MEM_freeN(op->customdata);
448 }
449
450 static int image_view_zoom_exec(bContext *C, wmOperator *op)
451 {
452         SpaceImage *sima = CTX_wm_space_image(C);
453         ARegion *ar = CTX_wm_region(C);
454
455         sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"), NULL);
456
457         ED_region_tag_redraw(ar);
458
459         /* XXX notifier? */
460 #if 0
461         if (image_preview_active(curarea, NULL, NULL)) {
462                 /* recalculates new preview rect */
463                 scrarea_do_windraw(curarea);
464                 image_preview_event(2);
465         }
466 #endif
467         
468         return OPERATOR_FINISHED;
469 }
470
471 enum {
472         VIEW_PASS = 0,
473         VIEW_APPLY,
474         VIEW_CONFIRM
475 };
476
477 static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
478 {
479         if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
480                 SpaceImage *sima = CTX_wm_space_image(C);
481                 ARegion *ar = CTX_wm_region(C);
482                 float delta, factor, location[2];
483
484                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
485
486                 delta = event->prevx - event->x + event->prevy - event->y;
487
488                 if (U.uiflag & USER_ZOOM_INVERT)
489                         delta *= -1;
490
491                 factor = 1.0f + delta / 300.0f;
492                 RNA_float_set(op->ptr, "factor", factor);
493                 sima_zoom_set(sima, ar, sima->zoom * factor, location);
494                 ED_region_tag_redraw(ar);
495                 
496                 return OPERATOR_FINISHED;
497         }
498         else {
499                 image_view_zoom_init(C, op, event);
500                 return OPERATOR_RUNNING_MODAL;
501         }
502 }
503
504 static void image_zoom_apply(ViewZoomData *vpd, wmOperator *op, const int x, const int y, const short viewzoom, const short zoom_invert)
505 {
506         float factor;
507
508         if (viewzoom == USER_ZOOM_CONT) {
509                 double time = PIL_check_seconds_timer();
510                 float time_step = (float)(time - vpd->timer_lastdraw);
511                 float fac;
512                 float zfac;
513
514                 if (U.uiflag & USER_ZOOM_HORIZ) {
515                         fac = (float)(x - vpd->origx);
516                 }
517                 else {
518                         fac = (float)(y - vpd->origy);
519                 }
520
521                 if (zoom_invert) {
522                         fac = -fac;
523                 }
524
525                 /* oldstyle zoom */
526                 zfac = 1.0f + ((fac / 20.0f) * time_step);
527                 vpd->timer_lastdraw = time;
528                 /* this is the final zoom, but instead make it into a factor */
529                 //zoom = vpd->sima->zoom * zfac;
530                 factor = (vpd->sima->zoom * zfac) / vpd->zoom;
531         }
532         else {
533                 /* for now do the same things for scale and dolly */
534                 float delta = x - vpd->origx + y - vpd->origy;
535
536                 if (zoom_invert)
537                         delta *= -1.0f;
538
539                 factor = 1.0f + delta / 300.0f;
540         }
541
542         RNA_float_set(op->ptr, "factor", factor);
543         sima_zoom_set(vpd->sima, vpd->ar, vpd->zoom * factor, vpd->location);
544         ED_region_tag_redraw(vpd->ar);
545 }
546
547 static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
548 {
549         ViewZoomData *vpd = op->customdata;
550         short event_code = VIEW_PASS;
551
552         /* execute the events */
553         if (event->type == TIMER && event->customdata == vpd->timer) {
554                 /* continuous zoom */
555                 event_code = VIEW_APPLY;
556         }
557         else if (event->type == MOUSEMOVE) {
558                 event_code = VIEW_APPLY;
559         }
560         else if (event->type == vpd->event_type && event->val == KM_RELEASE) {
561                 event_code = VIEW_CONFIRM;
562         }
563
564         if (event_code == VIEW_APPLY) {
565                 image_zoom_apply(vpd, op, event->x, event->y, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
566         }
567         else if (event_code == VIEW_CONFIRM) {
568                 image_view_zoom_exit(C, op, false);
569                 return OPERATOR_FINISHED;
570         }
571
572         return OPERATOR_RUNNING_MODAL;
573 }
574
575 static void image_view_zoom_cancel(bContext *C, wmOperator *op)
576 {
577         image_view_zoom_exit(C, op, true);
578 }
579
580 void IMAGE_OT_view_zoom(wmOperatorType *ot)
581 {
582         PropertyRNA *prop;
583
584         /* identifiers */
585         ot->name = "View Zoom";
586         ot->idname = "IMAGE_OT_view_zoom";
587         ot->description = "Zoom in/out the image";
588         
589         /* api callbacks */
590         ot->exec = image_view_zoom_exec;
591         ot->invoke = image_view_zoom_invoke;
592         ot->modal = image_view_zoom_modal;
593         ot->cancel = image_view_zoom_cancel;
594         ot->poll = space_image_main_area_poll;
595
596         /* flags */
597         ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
598         
599         /* properties */
600         prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
601                              "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
602         RNA_def_property_flag(prop, PROP_HIDDEN);
603 }
604
605 /********************** NDOF operator *********************/
606
607 /* Combined pan/zoom from a 3D mouse device.
608  * Z zooms, XY pans
609  * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
610  * that explains the negative signs in the code below
611  */
612
613 static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
614 {
615         if (event->type != NDOF_MOTION)
616                 return OPERATOR_CANCELLED;
617         else {
618                 SpaceImage *sima = CTX_wm_space_image(C);
619                 ARegion *ar = CTX_wm_region(C);
620                 float pan_vec[3];
621
622                 const wmNDOFMotionData *ndof = event->customdata;
623                 const float speed = NDOF_PIXELS_PER_SECOND;
624
625                 WM_event_ndof_pan_get(ndof, pan_vec, true);
626
627                 mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom);
628                 pan_vec[2] *= -ndof->dt;
629
630                 sima_zoom_set_factor(sima, ar, 1.0f + pan_vec[2], NULL);
631                 sima->xof += pan_vec[0];
632                 sima->yof += pan_vec[1];
633
634                 ED_region_tag_redraw(ar);
635
636                 return OPERATOR_FINISHED;
637         }
638 }
639
640 void IMAGE_OT_view_ndof(wmOperatorType *ot)
641 {
642         /* identifiers */
643         ot->name = "NDOF Pan/Zoom";
644         ot->idname = "IMAGE_OT_view_ndof";
645         ot->description = "Use a 3D mouse device to pan/zoom the view";
646         
647         /* api callbacks */
648         ot->invoke = image_view_ndof_invoke;
649         ot->poll = space_image_main_area_poll;
650
651         /* flags */
652         ot->flag = OPTYPE_LOCK_BYPASS;
653 }
654
655 /********************** view all operator *********************/
656
657 /* Updates the fields of the View2D member of the SpaceImage struct.
658  * Default behavior is to reset the position of the image and set the zoom to 1
659  * If the image will not fit within the window rectangle, the zoom is adjusted */
660
661 static int image_view_all_exec(bContext *C, wmOperator *op)
662 {
663         SpaceImage *sima;
664         ARegion *ar;
665         float aspx, aspy, zoomx, zoomy, w, h;
666         int width, height;
667         const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
668
669         /* retrieve state */
670         sima = CTX_wm_space_image(C);
671         ar = CTX_wm_region(C);
672
673         ED_space_image_get_size(sima, &width, &height);
674         ED_space_image_get_aspect(sima, &aspx, &aspy);
675
676         w = width * aspx;
677         h = height * aspy;
678         
679         /* check if the image will fit in the image with (zoom == 1) */
680         width  = BLI_rcti_size_x(&ar->winrct) + 1;
681         height = BLI_rcti_size_y(&ar->winrct) + 1;
682
683         if (fit_view) {
684                 const int margin = 5; /* margin from border */
685
686                 zoomx = (float) width / (w + 2 * margin);
687                 zoomy = (float) height / (h + 2 * margin);
688
689                 sima_zoom_set(sima, ar, min_ff(zoomx, zoomy), NULL);
690         }
691         else {
692                 if ((w >= width || h >= height) && (width > 0 && height > 0)) {
693                         zoomx = (float) width / w;
694                         zoomy = (float) height / h;
695
696                         /* find the zoom value that will fit the image in the image space */
697                         sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL);
698                 }
699                 else
700                         sima_zoom_set(sima, ar, 1.0f, NULL);
701         }
702
703         sima->xof = sima->yof = 0.0f;
704
705         ED_region_tag_redraw(ar);
706         
707         return OPERATOR_FINISHED;
708 }
709
710 void IMAGE_OT_view_all(wmOperatorType *ot)
711 {
712         PropertyRNA *prop;
713
714         /* identifiers */
715         ot->name = "View All";
716         ot->idname = "IMAGE_OT_view_all";
717         ot->description = "View the entire image";
718         
719         /* api callbacks */
720         ot->exec = image_view_all_exec;
721         ot->poll = space_image_main_area_poll;
722
723         /* properties */
724         prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
725         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
726 }
727
728 /********************** view selected operator *********************/
729
730 static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
731 {
732         SpaceImage *sima;
733         ARegion *ar;
734         Scene *scene;
735         Object *obedit;
736         Image *ima;
737         float size, min[2], max[2], d[2], aspx, aspy;
738         int width, height;
739
740         /* retrieve state */
741         sima = CTX_wm_space_image(C);
742         ar = CTX_wm_region(C);
743         scene = CTX_data_scene(C);
744         obedit = CTX_data_edit_object(C);
745
746         ima = ED_space_image(sima);
747         ED_space_image_get_size(sima, &width, &height);
748         ED_space_image_get_aspect(sima, &aspx, &aspy);
749
750         width = width * aspx;
751         height = height * aspy;
752
753         /* get bounds */
754         if (!ED_uvedit_minmax(scene, ima, obedit, min, max))
755                 return OPERATOR_CANCELLED;
756
757         /* adjust offset and zoom */
758         sima->xof = (int)(((min[0] + max[0]) * 0.5f - 0.5f) * width);
759         sima->yof = (int)(((min[1] + max[1]) * 0.5f - 0.5f) * height);
760
761         d[0] = max[0] - min[0];
762         d[1] = max[1] - min[1];
763         size = 0.5f * MAX2(d[0], d[1]) * MAX2(width, height) / 256.0f;
764         
765         if (size <= 0.01f) size = 0.01f;
766         sima_zoom_set(sima, ar, 0.7f / size, NULL);
767
768         ED_region_tag_redraw(ar);
769         
770         return OPERATOR_FINISHED;
771 }
772
773 static int image_view_selected_poll(bContext *C)
774 {
775         return (space_image_main_area_poll(C) && ED_operator_uvedit(C));
776 }
777
778 void IMAGE_OT_view_selected(wmOperatorType *ot)
779 {
780         /* identifiers */
781         ot->name = "View Center";
782         ot->idname = "IMAGE_OT_view_selected";
783         ot->description = "View all selected UVs";
784         
785         /* api callbacks */
786         ot->exec = image_view_selected_exec;
787         ot->poll = image_view_selected_poll;
788 }
789
790 /********************** view zoom in/out operator *********************/
791
792 static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
793 {
794         SpaceImage *sima = CTX_wm_space_image(C);
795         ARegion *ar = CTX_wm_region(C);
796         float location[2];
797         
798         RNA_float_get_array(op->ptr, "location", location);
799
800         sima_zoom_set_factor(sima, ar, powf(2.0f, 1.0f / 3.0f), location);
801
802         ED_region_tag_redraw(ar);
803         
804         return OPERATOR_FINISHED;
805 }
806
807 static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
808 {
809         ARegion *ar = CTX_wm_region(C);
810         float location[2];
811
812         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
813         RNA_float_set_array(op->ptr, "location", location);
814
815         return image_view_zoom_in_exec(C, op);
816 }
817
818 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
819 {
820         PropertyRNA *prop;
821
822         /* identifiers */
823         ot->name = "View Zoom In";
824         ot->idname = "IMAGE_OT_view_zoom_in";
825         ot->description = "Zoom in the image (centered around 2D cursor)";
826         
827         /* api callbacks */
828         ot->invoke = image_view_zoom_in_invoke;
829         ot->exec = image_view_zoom_in_exec;
830         ot->poll = space_image_main_area_poll;
831
832         /* flags */
833         ot->flag = OPTYPE_LOCK_BYPASS;
834
835         /* properties */
836         prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
837                                     "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
838         RNA_def_property_flag(prop, PROP_HIDDEN);
839 }
840
841 static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
842 {
843         SpaceImage *sima = CTX_wm_space_image(C);
844         ARegion *ar = CTX_wm_region(C);
845         float location[2];
846         
847         RNA_float_get_array(op->ptr, "location", location);
848
849         sima_zoom_set_factor(sima, ar, powf(0.5f, 1.0f / 3.0f), location);
850         
851         ED_region_tag_redraw(ar);
852         
853         return OPERATOR_FINISHED;
854 }
855
856 static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
857 {
858         ARegion *ar = CTX_wm_region(C);
859         float location[2];
860
861         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
862         RNA_float_set_array(op->ptr, "location", location);
863
864         return image_view_zoom_out_exec(C, op);
865 }
866
867 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
868 {
869         PropertyRNA *prop;
870
871         /* identifiers */
872         ot->name = "View Zoom Out";
873         ot->idname = "IMAGE_OT_view_zoom_out";
874         ot->description = "Zoom out the image (centered around 2D cursor)";
875         
876         /* api callbacks */
877         ot->invoke = image_view_zoom_out_invoke;
878         ot->exec = image_view_zoom_out_exec;
879         ot->poll = space_image_main_area_poll;
880
881         /* flags */
882         ot->flag = OPTYPE_LOCK_BYPASS;
883
884         /* properties */
885         prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
886                                     "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
887         RNA_def_property_flag(prop, PROP_HIDDEN);
888 }
889
890 /********************** view zoom ratio operator *********************/
891
892 static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
893 {
894         SpaceImage *sima = CTX_wm_space_image(C);
895         ARegion *ar = CTX_wm_region(C);
896
897         sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"), NULL);
898         
899         /* ensure pixel exact locations for draw */
900         sima->xof = (int)sima->xof;
901         sima->yof = (int)sima->yof;
902
903         /* XXX notifier? */
904 #if 0
905         if (image_preview_active(curarea, NULL, NULL)) {
906                 /* recalculates new preview rect */
907                 scrarea_do_windraw(curarea);
908                 image_preview_event(2);
909         }
910 #endif
911
912         ED_region_tag_redraw(ar);
913         
914         return OPERATOR_FINISHED;
915 }
916
917 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
918 {
919         /* identifiers */
920         ot->name = "View Zoom Ratio";
921         ot->idname = "IMAGE_OT_view_zoom_ratio";
922         ot->description = "Set zoom ratio of the view";
923         
924         /* api callbacks */
925         ot->exec = image_view_zoom_ratio_exec;
926         ot->poll = space_image_main_area_poll;
927
928         /* flags */
929         ot->flag = OPTYPE_LOCK_BYPASS;
930
931         /* properties */
932         RNA_def_float(ot->srna, "ratio", 0.0f, -FLT_MAX, FLT_MAX,
933                       "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX);
934 }
935
936 /**************** load/replace/save callbacks ******************/
937 static void image_filesel(bContext *C, wmOperator *op, const char *path)
938 {
939         RNA_string_set(op->ptr, "filepath", path);
940         WM_event_add_fileselect(C, op); 
941 }
942
943 /******************** open image operator ********************/
944
945 typedef struct ImageOpenData {
946         PropertyPointerRNA pprop;
947         ImageUser *iuser;
948         ImageFormatData im_format;
949 } ImageOpenData;
950
951 typedef struct ImageFrame {
952         struct ImageFrame *next, *prev;
953         int framenr;
954 } ImageFrame;
955
956 static void image_open_init(bContext *C, wmOperator *op)
957 {
958         ImageOpenData *iod;
959         op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
960         iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
961         UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
962 }
963
964 static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
965 {
966         MEM_freeN(op->customdata);
967         op->customdata = NULL;
968 }
969
970 /**
971  * \brief Get a list of frames from the list of image files matching the first file name sequence pattern
972  * \param ptr [in] the RNA pointer containing the "directory" entry and "files" collection
973  * \param frames [out] the list of frame numbers found in the files matching the first one by name
974  * \param path [out] the full path of the first file in the list of image files
975  */
976 static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen)
977 {
978         char dir[FILE_MAXDIR];
979         bool is_first_entry = true;
980
981         RNA_string_get(ptr, "directory", dir);
982         RNA_BEGIN (ptr, itemptr, "files")
983         {
984                 char base_head[FILE_MAX], base_tail[FILE_MAX];
985                 char head[FILE_MAX], tail[FILE_MAX];
986                 unsigned short digits;
987                 char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
988                 ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
989
990                 /* use the first file in the list as base filename */
991                 if (is_first_entry) {
992                         BLI_join_dirfile(path, maxlen, dir, filename);
993                         frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits);
994                         BLI_addtail(frames, frame);
995                         is_first_entry = false;
996                 }
997                 else {
998                         frame->framenr = BLI_stringdec(filename, head, tail, &digits);
999
1000                         /* still in the same sequence */
1001                         if ((STREQLEN(base_head, head, FILE_MAX)) &&
1002                             (STREQLEN(base_tail, tail, FILE_MAX)))
1003                         {
1004                                 BLI_addtail(frames, frame);
1005                         }
1006                         else {
1007                                 /* different file base name found, is ignored */
1008                                 MEM_freeN(frame);
1009                                 break;
1010                         }
1011                 }
1012
1013                 MEM_freeN(filename);
1014         }
1015         RNA_END
1016 }
1017
1018 static int image_cmp_frame(const void *a, const void *b)
1019 {
1020         const ImageFrame *frame_a = a;
1021         const ImageFrame *frame_b = b;
1022
1023         if (frame_a->framenr < frame_b->framenr) return -1;
1024         if (frame_a->framenr > frame_b->framenr) return 1;
1025         return 0;
1026 }
1027
1028 /**
1029  * \brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames
1030  * \param frames [in] the list of frame numbers, as a side-effect the list is sorted
1031  * \param ofs [out] offest, the first frame number in the sequence
1032  * \return the number of contiguous frames in the sequence
1033  */
1034 static int image_sequence_get_len(ListBase *frames, int *ofs)
1035 {
1036         ImageFrame *frame;
1037
1038         BLI_listbase_sort(frames, image_cmp_frame);
1039
1040         frame = frames->first;
1041         if (frame) {
1042                 int frame_curr = frame->framenr;
1043                 (*ofs) = frame_curr;
1044                 while (frame && (frame->framenr == frame_curr)) {
1045                         frame_curr++;
1046                         frame = frame->next;
1047                 }
1048                 return frame_curr - (*ofs);
1049         }
1050         return 0;
1051 }
1052
1053 static int image_open_exec(bContext *C, wmOperator *op)
1054 {
1055         Main *bmain = CTX_data_main(C);
1056         SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1057         Scene *scene = CTX_data_scene(C);
1058         Object *obedit = CTX_data_edit_object(C);
1059         ImageUser *iuser = NULL;
1060         ImageOpenData *iod = op->customdata;
1061         PointerRNA idptr;
1062         Image *ima = NULL;
1063         char path[FILE_MAX];
1064         int frame_seq_len = 0;
1065         int frame_ofs = 1;
1066         bool exists = false;
1067
1068         const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
1069
1070         RNA_string_get(op->ptr, "filepath", path);
1071
1072         if (!IMB_isanim(path) && RNA_struct_property_is_set(op->ptr, "files") &&
1073             RNA_struct_property_is_set(op->ptr, "directory"))
1074         {
1075                 ListBase frames;
1076
1077                 BLI_listbase_clear(&frames);
1078                 image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
1079                 frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
1080                 BLI_freelistN(&frames);
1081         }
1082
1083         errno = 0;
1084
1085         ima = BKE_image_load_exists_ex(path, &exists);
1086
1087         if (!ima) {
1088                 if (op->customdata) MEM_freeN(op->customdata);
1089                 BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
1090                             path, errno ? strerror(errno) : TIP_("unsupported image format"));
1091                 return OPERATOR_CANCELLED;
1092         }
1093
1094         if (!op->customdata)
1095                 image_open_init(C, op);
1096
1097         /* handle multiview images */
1098         if (RNA_boolean_get(op->ptr, "use_multiview")) {
1099                 ImageFormatData *imf = &iod->im_format;
1100
1101                 ima->flag |= IMA_USE_VIEWS;
1102                 ima->views_format = imf->views_format;
1103                 *ima->stereo3d_format = imf->stereo3d_format;
1104         }
1105         else {
1106                 ima->flag &= ~IMA_USE_VIEWS;
1107                 ima->flag &= ~IMA_IS_STEREO;
1108                 ima->flag &= ~IMA_IS_MULTIVIEW;
1109                 BKE_image_free_views(ima);
1110         }
1111
1112         /* only image path after save, never ibuf */
1113         if (is_relative_path) {
1114                 if (!exists) {
1115                         BLI_path_rel(ima->name, bmain->name);
1116                 }
1117         }
1118
1119         /* hook into UI */
1120         iod = op->customdata;
1121
1122         if (iod->pprop.prop) {
1123                 /* when creating new ID blocks, use is already 1, but RNA
1124                  * pointer se also increases user, so this compensates it */
1125                 ima->id.us--;
1126                 if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) {
1127                         ima->source = IMA_SRC_SEQUENCE;
1128                 }
1129                 RNA_id_pointer_create(&ima->id, &idptr);
1130                 RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr);
1131                 RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1132         }
1133
1134         if (iod->iuser) {
1135                 iuser = iod->iuser;
1136         }
1137         else if (sima) {
1138                 ED_space_image_set(sima, scene, obedit, ima);
1139                 iuser = &sima->iuser;
1140         }
1141         else {
1142                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1143                 if (tex && tex->type == TEX_IMAGE) {
1144                         iuser = &tex->iuser;
1145                 }
1146         }
1147
1148         /* initialize because of new image */
1149         if (iuser) {
1150                 iuser->frames = frame_seq_len;
1151                 iuser->sfra = 1;
1152                 iuser->framenr = 1;
1153                 iuser->offset = frame_ofs - 1;
1154                 iuser->fie_ima = 2;
1155                 iuser->scene = scene;
1156                 BKE_image_init_imageuser(ima, iuser);
1157         }
1158
1159         /* XXX unpackImage frees image buffers */
1160         ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1161         
1162         BKE_image_signal(ima, iuser, IMA_SIGNAL_RELOAD);
1163         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1164         
1165         MEM_freeN(op->customdata);
1166
1167         return OPERATOR_FINISHED;
1168 }
1169
1170 static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1171 {
1172         SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1173         const char *path = U.textudir;
1174         Image *ima = NULL;
1175         Scene *scene = CTX_data_scene(C);
1176         PropertyRNA *prop;
1177         if (sima) {
1178                 ima = sima->image;
1179         }
1180
1181         if (ima == NULL) {
1182                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1183                 if (tex && tex->type == TEX_IMAGE)
1184                         ima = tex->ima;
1185         }
1186
1187         if (ima == NULL) {
1188                 PointerRNA ptr;
1189                 PropertyRNA *prop;
1190
1191                 /* hook into UI */
1192                 UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
1193
1194                 if (prop) {
1195                         PointerRNA oldptr;
1196                         Image *oldima;
1197
1198                         oldptr = RNA_property_pointer_get(&ptr, prop);
1199                         oldima = (Image *)oldptr.id.data;
1200                         /* unlikely to fail but better avoid strange crash */
1201                         if (oldima && GS(oldima->id.name) == ID_IM) {
1202                                 ima = oldima;
1203                         }
1204                 }
1205         }
1206
1207         if (ima)
1208                 path = ima->name;
1209
1210         if (RNA_struct_property_is_set(op->ptr, "filepath"))
1211                 return image_open_exec(C, op);
1212         
1213         image_open_init(C, op);
1214
1215         /* show multiview save options only if scene has multiviews */
1216         prop = RNA_struct_find_property(op->ptr, "show_multiview");
1217         RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1218
1219         image_filesel(C, op, path);
1220
1221         return OPERATOR_RUNNING_MODAL;
1222 }
1223
1224 static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
1225 {
1226         const char *prop_id = RNA_property_identifier(prop);
1227
1228         return !(STREQ(prop_id, "filepath") ||
1229                  STREQ(prop_id, "directory") ||
1230                  STREQ(prop_id, "filename")
1231                  );
1232 }
1233
1234 static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
1235 {
1236         uiLayout *layout = op->layout;
1237         ImageOpenData *iod = op->customdata;
1238         ImageFormatData *imf = &iod->im_format;
1239         PointerRNA imf_ptr, ptr;
1240
1241         /* main draw call */
1242         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1243         uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, '\0');
1244
1245         /* image template */
1246         RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1247
1248         /* multiview template */
1249         if (RNA_boolean_get(op->ptr, "show_multiview"))
1250                 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1251 }
1252
1253 /* called by other space types too */
1254 void IMAGE_OT_open(wmOperatorType *ot)
1255 {
1256         /* identifiers */
1257         ot->name = "Open Image";
1258         ot->description = "Open image";
1259         ot->idname = "IMAGE_OT_open";
1260         
1261         /* api callbacks */
1262         ot->exec = image_open_exec;
1263         ot->invoke = image_open_invoke;
1264         ot->cancel = image_open_cancel;
1265         ot->ui = image_open_draw;
1266
1267         /* flags */
1268         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1269
1270         /* properties */
1271         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
1272                                        WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
1273 }
1274
1275 /******************** Match movie length operator ********************/
1276 static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
1277 {
1278         Scene *scene = CTX_data_scene(C);
1279         Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data;
1280         ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data;
1281
1282         if (!ima || !iuser) {
1283                 /* Try to get a Texture, or a SpaceImage from context... */
1284                 SpaceImage *sima = CTX_wm_space_image(C);
1285                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1286                 if (tex && tex->type == TEX_IMAGE) {
1287                         ima = tex->ima;
1288                         iuser = &tex->iuser;
1289                 }
1290                 else if (sima) {
1291                         ima = sima->image;
1292                         iuser = &sima->iuser;
1293                 }
1294                 
1295         }
1296
1297         if (!ima || !iuser || !BKE_image_has_anim(ima))
1298                 return OPERATOR_CANCELLED;
1299
1300         iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN);
1301         BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
1302
1303         return OPERATOR_FINISHED;
1304 }
1305
1306 /* called by other space types too */
1307 void IMAGE_OT_match_movie_length(wmOperatorType *ot)
1308 {
1309         /* identifiers */
1310         ot->name = "Match Movie Length";
1311         ot->description = "Set image's user's length to the one of this video";
1312         ot->idname = "IMAGE_OT_match_movie_length";
1313         
1314         /* api callbacks */
1315         ot->exec = image_match_len_exec;
1316
1317         /* flags */
1318         ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL/* | OPTYPE_UNDO */; /* Don't think we need undo for that. */
1319 }
1320
1321 /******************** replace image operator ********************/
1322
1323 static int image_replace_exec(bContext *C, wmOperator *op)
1324 {
1325         SpaceImage *sima = CTX_wm_space_image(C);
1326         char str[FILE_MAX];
1327
1328         if (!sima->image)
1329                 return OPERATOR_CANCELLED;
1330         
1331         RNA_string_get(op->ptr, "filepath", str);
1332
1333         /* we cant do much if the str is longer then FILE_MAX :/ */
1334         BLI_strncpy(sima->image->name, str, sizeof(sima->image->name));
1335
1336         if (sima->image->source == IMA_SRC_GENERATED) {
1337                 sima->image->source = IMA_SRC_FILE;
1338                 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1339         }
1340         
1341         if (BLI_testextensie_array(str, imb_ext_movie))
1342                 sima->image->source = IMA_SRC_MOVIE;
1343         else
1344                 sima->image->source = IMA_SRC_FILE;
1345
1346         /* XXX unpackImage frees image buffers */
1347         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1348         
1349         BKE_icon_changed(BKE_icon_getid(&sima->image->id));
1350         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1351         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1352
1353         return OPERATOR_FINISHED;
1354 }
1355
1356 static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1357 {
1358         SpaceImage *sima = CTX_wm_space_image(C);
1359
1360         if (!sima->image)
1361                 return OPERATOR_CANCELLED;
1362
1363         if (RNA_struct_property_is_set(op->ptr, "filepath"))
1364                 return image_replace_exec(C, op);
1365
1366         if (!RNA_struct_property_is_set(op->ptr, "relative_path"))
1367                 RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->name));
1368
1369         image_filesel(C, op, sima->image->name);
1370
1371         return OPERATOR_RUNNING_MODAL;
1372 }
1373
1374 void IMAGE_OT_replace(wmOperatorType *ot)
1375 {
1376         /* identifiers */
1377         ot->name = "Replace Image";
1378         ot->idname = "IMAGE_OT_replace";
1379         ot->description = "Replace current image by another one from disk";
1380         
1381         /* api callbacks */
1382         ot->exec = image_replace_exec;
1383         ot->invoke = image_replace_invoke;
1384         ot->poll = space_image_poll;
1385
1386         /* flags */
1387         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1388
1389         /* properties */
1390         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
1391                                        WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
1392 }
1393
1394 /******************** save image as operator ********************/
1395
1396 typedef struct {
1397         /* matching scene->r settings */
1398         //short planes, imtype, subimtype, quality;
1399         ImageFormatData im_format;
1400         char filepath[FILE_MAX]; /* keep absolute */
1401 } SaveImageOptions;
1402
1403 static void save_image_options_defaults(SaveImageOptions *simopts)
1404 {
1405         BKE_imformat_defaults(&simopts->im_format);
1406         simopts->filepath[0] = '\0';
1407 }
1408
1409 static char imtype_best_depth(ImBuf *ibuf, const char imtype)
1410 {
1411         const char depth_ok = BKE_imtype_valid_depths(imtype);
1412
1413         if (ibuf->rect_float) {
1414                 if (depth_ok & R_IMF_CHAN_DEPTH_32) return R_IMF_CHAN_DEPTH_32;
1415                 if (depth_ok & R_IMF_CHAN_DEPTH_24) return R_IMF_CHAN_DEPTH_24;
1416                 if (depth_ok & R_IMF_CHAN_DEPTH_16) return R_IMF_CHAN_DEPTH_16;
1417                 if (depth_ok & R_IMF_CHAN_DEPTH_12) return R_IMF_CHAN_DEPTH_12;
1418                 return R_IMF_CHAN_DEPTH_8;
1419         }
1420         else {
1421                 if (depth_ok & R_IMF_CHAN_DEPTH_8) return R_IMF_CHAN_DEPTH_8;
1422                 if (depth_ok & R_IMF_CHAN_DEPTH_12) return R_IMF_CHAN_DEPTH_12;
1423                 if (depth_ok & R_IMF_CHAN_DEPTH_16) return R_IMF_CHAN_DEPTH_16;
1424                 if (depth_ok & R_IMF_CHAN_DEPTH_24) return R_IMF_CHAN_DEPTH_24;
1425                 if (depth_ok & R_IMF_CHAN_DEPTH_32) return R_IMF_CHAN_DEPTH_32;
1426                 return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
1427         }
1428 }
1429
1430 static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, Scene *scene,
1431                                    const bool guess_path, const bool save_as_render)
1432 {
1433         void *lock;
1434         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
1435
1436         if (ibuf) {
1437                 Image *ima = sima->image;
1438                 bool is_depth_set = false;
1439
1440                 if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
1441                         /* imtype */
1442                         simopts->im_format = scene->r.im_format;
1443                         is_depth_set = true;
1444                 }
1445                 else {
1446                         if (ima->source == IMA_SRC_GENERATED) {
1447                                 simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
1448                         }
1449                         else {
1450                                 BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
1451                                 simopts->im_format.quality = ibuf->ftype & 0xff;
1452                         }
1453                         simopts->im_format.quality = ibuf->ftype & 0xff;
1454                 }
1455
1456                 simopts->im_format.planes = ibuf->planes;
1457
1458                 //simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */
1459
1460                 BLI_strncpy(simopts->filepath, ibuf->name, sizeof(simopts->filepath));
1461
1462                 /* sanitize all settings */
1463
1464                 /* unlikely but just in case */
1465                 if (ELEM(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
1466                         simopts->im_format.planes = R_IMF_PLANES_RGBA;
1467                 }
1468
1469                 /* depth, account for float buffer and format support */
1470                 if (is_depth_set == false) {
1471                         simopts->im_format.depth = imtype_best_depth(ibuf, simopts->im_format.imtype);
1472                 }
1473
1474                 /* some formats don't use quality so fallback to scenes quality */
1475                 if (simopts->im_format.quality == 0) {
1476                         simopts->im_format.quality = scene->r.im_format.quality;
1477                 }
1478
1479                 /* check for empty path */
1480                 if (guess_path && simopts->filepath[0] == 0) {
1481                         const bool is_prev_save = !STREQ(G.ima, "//");
1482                         if (save_as_render) {
1483                                 if (is_prev_save) {
1484                                         BLI_strncpy(simopts->filepath, G.ima, sizeof(simopts->filepath));
1485                                 }
1486                                 else {
1487                                         BLI_strncpy(simopts->filepath, "//untitled", sizeof(simopts->filepath));
1488                                         BLI_path_abs(simopts->filepath, G.main->name);
1489                                 }
1490                         }
1491                         else {
1492                                 BLI_snprintf(simopts->filepath, sizeof(simopts->filepath), "//%s", ima->id.name + 2);
1493                                 BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : G.main->name);
1494                         }
1495                 }
1496
1497                 /* use the multiview image settings as the default */
1498                 simopts->im_format.stereo3d_format = *ima->stereo3d_format;
1499                 simopts->im_format.views_format = ima->views_format;
1500
1501                 /* color management */
1502                 BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
1503                 BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
1504         }
1505
1506         ED_space_image_release_buffer(sima, ibuf, lock);
1507
1508         return (ibuf != NULL);
1509 }
1510
1511 static void save_image_options_from_op(SaveImageOptions *simopts, wmOperator *op)
1512 {
1513         if (op->customdata) {
1514                 BKE_color_managed_view_settings_free(&simopts->im_format.view_settings);
1515
1516                 simopts->im_format = *(ImageFormatData *)op->customdata;
1517         }
1518
1519         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1520                 RNA_string_get(op->ptr, "filepath", simopts->filepath);
1521                 BLI_path_abs(simopts->filepath, G.main->name);
1522         }
1523 }
1524
1525 static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
1526 {
1527         if (op->customdata) {
1528                 BKE_color_managed_view_settings_free(&((ImageFormatData *)op->customdata)->view_settings);
1529
1530                 *(ImageFormatData *)op->customdata = simopts->im_format;
1531         }
1532
1533         RNA_string_set(op->ptr, "filepath", simopts->filepath);
1534 }
1535
1536 /* returns the pass index for the view_id */
1537 static int get_multiview_pass_id(RenderResult *rr, ImageUser *iuser, const int view_id)
1538 {
1539         RenderLayer *rl;
1540         RenderPass *rpass;
1541         int passtype;
1542         short rl_index = 0, rp_index;
1543
1544         if (rr == NULL || iuser == NULL)
1545                 return 0;
1546
1547         if (BLI_listbase_count_ex(&rr->views, 2) < 2)
1548                 return iuser->pass;
1549
1550         if (RE_HasFakeLayer(rr))
1551                 rl_index ++; /* fake compo/sequencer layer */
1552
1553         rl = BLI_findlink(&rr->layers, rl_index);
1554         if (!rl) return iuser->pass;
1555
1556         rpass = BLI_findlink(&rl->passes, iuser->pass);
1557         passtype = rpass->passtype;
1558
1559         rp_index = 0;
1560         for (rpass = rl->passes.first; rpass; rpass = rpass->next, rp_index++) {
1561                 if (rpass->passtype == passtype &&
1562                     rpass->view_id == view_id)
1563                 {
1564                         return rp_index;
1565                 }
1566         }
1567
1568         return iuser->pass;
1569 }
1570
1571 static void save_image_post(wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy, const char *relbase, int relative, int do_newpath, const char *filepath)
1572 {
1573         if (ok) {
1574                 if (!save_copy) {
1575                         if (do_newpath) {
1576                                 BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
1577                                 BLI_strncpy(ima->name, filepath, sizeof(ima->name));
1578                         }
1579
1580                         ibuf->userflags &= ~IB_BITMAPDIRTY;
1581
1582                         /* change type? */
1583                         if (ima->type == IMA_TYPE_R_RESULT) {
1584                                 ima->type = IMA_TYPE_IMAGE;
1585
1586                                 /* workaround to ensure the render result buffer is no longer used
1587                                  * by this image, otherwise can crash when a new render result is
1588                                  * created. */
1589                                 if (ibuf->rect && !(ibuf->mall & IB_rect))
1590                                         imb_freerectImBuf(ibuf);
1591                                 if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
1592                                         imb_freerectfloatImBuf(ibuf);
1593                                 if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
1594                                         IMB_freezbufImBuf(ibuf);
1595                                 if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
1596                                         IMB_freezbuffloatImBuf(ibuf);
1597                         }
1598                         if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
1599                                 ima->source = IMA_SRC_FILE;
1600                                 ima->type = IMA_TYPE_IMAGE;
1601                         }
1602
1603                         /* only image path, never ibuf */
1604                         if (relative) {
1605                                 BLI_path_rel(ima->name, relbase); /* only after saving */
1606                         }
1607
1608                         IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
1609
1610                 }
1611         }
1612         else {
1613                 BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", filepath);
1614         }
1615 }
1616
1617 static void save_imbuf_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
1618 {
1619         if (colormanaged_ibuf != ibuf) {
1620                 /* This guys might be modified by image buffer write functions,
1621                  * need to copy them back from color managed image buffer to an
1622                  * original one, so file type of image is being properly updated.
1623                  */
1624                 ibuf->ftype = colormanaged_ibuf->ftype;
1625                 ibuf->planes = colormanaged_ibuf->planes;
1626
1627                 IMB_freeImBuf(colormanaged_ibuf);
1628         }
1629 }
1630
1631 /**
1632  * \return success.
1633  * \note ``ima->name`` and ``ibuf->name`` should end up the same.
1634  * \note for multiview the first ``ibuf`` is important to get the settings.
1635  */
1636 static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
1637 {
1638         Image *ima = ED_space_image(sima);
1639         void *lock;
1640         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
1641         Scene *scene;
1642         RenderResult *rr = NULL;
1643         bool ok = false;
1644
1645         WM_cursor_wait(1);
1646
1647         if (ibuf) {
1648                 ImBuf *colormanaged_ibuf = NULL;
1649                 const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
1650                 const bool relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
1651                 const bool save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
1652                 const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
1653                 ImageFormatData *imf = &simopts->im_format;
1654
1655                 const bool is_multilayer = imf->imtype == R_IMF_IMTYPE_MULTILAYER;
1656                 bool is_mono;
1657
1658                 /* old global to ensure a 2nd save goes to same dir */
1659                 BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima));
1660
1661                 if (ima->type == IMA_TYPE_R_RESULT) {
1662                         /* enforce user setting for RGB or RGBA, but skip BW */
1663                         if (simopts->im_format.planes == R_IMF_PLANES_RGBA) {
1664                                 ibuf->planes = R_IMF_PLANES_RGBA;
1665                         }
1666                         else if (simopts->im_format.planes == R_IMF_PLANES_RGB) {
1667                                 ibuf->planes = R_IMF_PLANES_RGB;
1668                         }
1669                 }
1670                 else {
1671                         /* TODO, better solution, if a 24bit image is painted onto it may contain alpha */
1672                         if ((simopts->im_format.planes == R_IMF_PLANES_RGBA) &&
1673                             /* it has been painted onto */
1674                             (ibuf->userflags & IB_BITMAPDIRTY))
1675                         {
1676                                 /* checks each pixel, not ideal */
1677                                 ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB;
1678                         }
1679                 }
1680
1681                 /* we need renderresult for exr and rendered multiview */
1682                 scene = CTX_data_scene(C);
1683                 rr = BKE_image_acquire_renderresult(scene, ima);
1684                 is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0;
1685
1686                 /* error handling */
1687                 if (!rr) {
1688                         if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
1689                                 BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
1690                                 goto cleanup;
1691                         }
1692                 }
1693                 else {
1694                         if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
1695                                 if ((ima->flag & IMA_IS_STEREO) == 0) {
1696                                         BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
1697                                                    STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
1698                                         goto cleanup;
1699                                 }
1700
1701                                 /* it shouldn't ever happen*/
1702                                 if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
1703                                     (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL))
1704                                 {
1705                                         BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
1706                                                    STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
1707                                         goto cleanup;
1708                                 }
1709                         }
1710                 }
1711
1712                 /* fancy multiview OpenEXR */
1713                 if ((imf->imtype == R_IMF_IMTYPE_MULTILAYER) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
1714                         ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, true, NULL);
1715                         save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
1716                         ED_space_image_release_buffer(sima, ibuf, lock);
1717                 }
1718                 else if ((imf->imtype == R_IMF_IMTYPE_OPENEXR) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
1719                         /* treat special Openexr case separetely (this is the singlelayer multiview OpenEXR */
1720                         BKE_imbuf_write_prepare(ibuf, imf);
1721                         ok = BKE_image_save_openexr_multiview(ima, ibuf, simopts->filepath, (IB_rect | IB_zbuf | IB_zbuffloat | IB_multiview));
1722                         ED_space_image_release_buffer(sima, ibuf, lock);
1723                 }
1724                 /* regular mono pipeline */
1725                 else if (is_mono) {
1726                         if (is_multilayer) {
1727                                 ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
1728                         }
1729                         else {
1730                                 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
1731                                 ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy);
1732                                 save_imbuf_post(ibuf, colormanaged_ibuf);
1733                         }
1734                         save_image_post(op, ibuf, ima, ok, (is_multilayer ? true : save_copy), relbase, relative, do_newpath, simopts->filepath);
1735                         ED_space_image_release_buffer(sima, ibuf, lock);
1736                 }
1737                 /* individual multiview images */
1738                 else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
1739                         size_t i;
1740                         unsigned char planes = ibuf->planes;
1741                         const size_t totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
1742
1743                         if (!is_multilayer) {
1744                                 ED_space_image_release_buffer(sima, ibuf, lock);
1745                         }
1746
1747                         for (i = 0; i < totviews; i++) {
1748                                 char filepath[FILE_MAX];
1749                                 bool ok_view = false;
1750                                 const char *view = rr ? ((RenderView *) BLI_findlink(&rr->views, i))->name :
1751                                                         ((ImageView *) BLI_findlink(&ima->views, i))->name;
1752
1753                                 if (is_multilayer) {
1754                                         BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
1755                                         ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, false, view);
1756                                         save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
1757                                 }
1758                                 else {
1759                                         /* copy iuser to get the correct ibuf for this view */
1760                                         ImageUser iuser = sima->iuser;
1761                                         iuser.view = i;
1762                                         iuser.flag &= ~IMA_SHOW_STEREO;
1763
1764                                         if (rr) {
1765                                                 iuser.pass = get_multiview_pass_id(rr, &sima->iuser, i);
1766                                                 BKE_image_multilayer_index(rr, &iuser);
1767                                         }
1768                                         else {
1769                                                 BKE_image_multiview_index(ima, &iuser);
1770                                         }
1771
1772                                         ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
1773                                         ibuf->planes = planes;
1774
1775                                         BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
1776
1777                                         colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
1778                                         ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &simopts->im_format, save_copy);
1779                                         save_imbuf_post(ibuf, colormanaged_ibuf);
1780                                         save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
1781                                         BKE_image_release_ibuf(sima->image, ibuf, lock);
1782                                 }
1783                                 ok &= ok_view;
1784                         }
1785
1786                         if (is_multilayer) {
1787                                 ED_space_image_release_buffer(sima, ibuf, lock);
1788                         }
1789                 }
1790                 /* stereo (multiview) images */
1791                 else if (simopts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
1792                         if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
1793                                 ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
1794                                 save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
1795                                 ED_space_image_release_buffer(sima, ibuf, lock);
1796                         }
1797                         else {
1798                                 ImBuf *ibuf_stereo[2] = {NULL};
1799
1800                                 unsigned char planes = ibuf->planes;
1801                                 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
1802                                 int i;
1803
1804                                 /* we need to get the specific per-view buffers */
1805                                 ED_space_image_release_buffer(sima, ibuf, lock);
1806
1807                                 for (i = 0; i < 2; i ++) {
1808                                         ImageUser iuser = sima->iuser;
1809                                         iuser.flag &= ~IMA_SHOW_STEREO;
1810
1811                                         if (rr) {
1812                                                 int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
1813                                                 iuser.pass = get_multiview_pass_id(rr, &sima->iuser, id);
1814                                                 iuser.view = id;
1815
1816                                                 BKE_image_multilayer_index(rr, &iuser);
1817                                         }
1818                                         else {
1819                                                 iuser.view = i;
1820                                                 BKE_image_multiview_index(ima, &iuser);
1821                                         }
1822
1823                                         ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
1824
1825                                         if (ibuf == NULL) {
1826                                                 BKE_report(op->reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
1827                                                 goto cleanup;
1828                                         }
1829
1830                                         ibuf->planes = planes;
1831
1832                                         /* color manage the ImBuf leaving it ready for saving */
1833                                         colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true,
1834                                                                                                 &imf->view_settings, &imf->display_settings, imf);
1835
1836                                         BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
1837                                         IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
1838
1839                                         /* duplicate buffer to prevent locker issue when using render result */
1840                                         ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
1841
1842                                         save_imbuf_post(ibuf, colormanaged_ibuf);
1843                                         BKE_image_release_ibuf(sima->image, ibuf, lock);
1844                                 }
1845
1846                                 ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
1847
1848                                 /* save via traditional path */
1849                                 ok = BKE_imbuf_write_as(ibuf, simopts->filepath, imf, save_copy);
1850
1851                                 IMB_freeImBuf(ibuf);
1852
1853                                 for (i = 0; i < 2; i ++) {
1854                                         IMB_freeImBuf(ibuf_stereo[i]);
1855                                 }
1856                         }
1857                 }
1858
1859                 WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1860
1861         }
1862         else {
1863 cleanup:
1864                 ED_space_image_release_buffer(sima, ibuf, lock);
1865         }
1866
1867         if (rr) {
1868                 BKE_image_release_renderresult(scene, ima);
1869         }
1870
1871         WM_cursor_wait(0);
1872
1873         return ok;
1874 }
1875
1876 static void image_save_as_free(wmOperator *op)
1877 {
1878         if (op->customdata) {
1879                 ImageFormatData *im_format = (ImageFormatData *)op->customdata;
1880                 BKE_color_managed_view_settings_free(&im_format->view_settings);
1881
1882                 MEM_freeN(op->customdata);
1883                 op->customdata = NULL;
1884         }
1885 }
1886
1887 static int image_save_as_exec(bContext *C, wmOperator *op)
1888 {
1889         SpaceImage *sima = CTX_wm_space_image(C);
1890         SaveImageOptions simopts;
1891
1892         save_image_options_defaults(&simopts);
1893
1894         /* just in case to initialize values,
1895          * these should be set on invoke or by the caller. */
1896         save_image_options_init(&simopts, sima, CTX_data_scene(C), false, false);
1897
1898         save_image_options_from_op(&simopts, op);
1899
1900         save_image_doit(C, sima, op, &simopts, true);
1901
1902         image_save_as_free(op);
1903         return OPERATOR_FINISHED;
1904 }
1905
1906
1907 static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
1908 {
1909         ImageFormatData *imf = op->customdata;
1910         return WM_operator_filesel_ensure_ext_imtype(op, imf);
1911 }
1912
1913 static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1914 {
1915         SpaceImage *sima = CTX_wm_space_image(C);
1916         Image *ima = ED_space_image(sima);
1917         Scene *scene = CTX_data_scene(C);
1918         SaveImageOptions simopts;
1919         PropertyRNA *prop;
1920         const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) || (ima->flag & IMA_VIEW_AS_RENDER));
1921
1922         if (RNA_struct_property_is_set(op->ptr, "filepath"))
1923                 return image_save_as_exec(C, op);
1924
1925         save_image_options_defaults(&simopts);
1926
1927         if (save_image_options_init(&simopts, sima, scene, true, save_as_render) == 0)
1928                 return OPERATOR_CANCELLED;
1929         save_image_options_to_op(&simopts, op);
1930
1931         /* enable save_copy by default for render results */
1932         if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) && !RNA_struct_property_is_set(op->ptr, "copy")) {
1933                 RNA_boolean_set(op->ptr, "copy", true);
1934         }
1935
1936         RNA_boolean_set(op->ptr, "save_as_render", save_as_render);
1937
1938         op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
1939         memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
1940
1941         /* show multiview save options only if image has multiviews */
1942         prop = RNA_struct_find_property(op->ptr, "show_multiview");
1943         RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
1944         prop = RNA_struct_find_property(op->ptr, "use_multiview");
1945         RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
1946
1947         image_filesel(C, op, simopts.filepath);
1948
1949         return OPERATOR_RUNNING_MODAL;
1950 }
1951
1952 static void image_save_as_cancel(bContext *UNUSED(C), wmOperator *op)
1953 {
1954         image_save_as_free(op);
1955 }
1956
1957 static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
1958 {
1959         const char *prop_id = RNA_property_identifier(prop);
1960
1961         return !(STREQ(prop_id, "filepath") ||
1962                  STREQ(prop_id, "directory") ||
1963                  STREQ(prop_id, "filename") ||
1964                  /* when saving a copy, relative path has no effect */
1965                  ((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy"))
1966                  );
1967 }
1968
1969 static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
1970 {
1971         uiLayout *layout = op->layout;
1972         ImageFormatData *imf = op->customdata;
1973         PointerRNA imf_ptr, ptr;
1974         const bool is_multiview = RNA_boolean_get(op->ptr, "use_multiview");
1975
1976         /* image template */
1977         RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1978         uiTemplateImageSettings(layout, &imf_ptr, false);
1979
1980         /* main draw call */
1981         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1982         uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0');
1983
1984         /* multiview template */
1985         if (is_multiview)
1986                 uiTemplateImageFormatViews(layout, &imf_ptr, NULL);
1987 }
1988
1989 static int image_save_as_poll(bContext *C)
1990 {
1991         if (space_image_buffer_exists_poll(C)) {
1992                 if (G.is_rendering) {
1993                         /* no need to NULL check here */
1994                         SpaceImage *sima = CTX_wm_space_image(C);
1995                         Image *ima = ED_space_image(sima);
1996
1997                         if (ima->source == IMA_SRC_VIEWER) {
1998                                 CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
1999                                 return false;
2000                         }
2001                 }
2002                 return true;
2003         }
2004         return false;
2005 }
2006
2007 void IMAGE_OT_save_as(wmOperatorType *ot)
2008 {
2009         /* identifiers */
2010         ot->name = "Save As Image";
2011         ot->idname = "IMAGE_OT_save_as";
2012         ot->description = "Save the image with another name and/or settings";
2013         
2014         /* api callbacks */
2015         ot->exec = image_save_as_exec;
2016         ot->check = image_save_as_check;
2017         ot->invoke = image_save_as_invoke;
2018         ot->cancel = image_save_as_cancel;
2019         ot->ui = image_save_as_draw;
2020         ot->poll = image_save_as_poll;
2021
2022         /* flags */
2023         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2024
2025         /* properties */
2026         RNA_def_boolean(ot->srna, "save_as_render", 0, "Save As Render", "Apply render part of display transform when saving byte image");
2027         RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
2028
2029         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
2030                                        WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
2031 }
2032
2033 /******************** save image operator ********************/
2034
2035 static int image_save_exec(bContext *C, wmOperator *op)
2036 {
2037         SpaceImage *sima = CTX_wm_space_image(C);
2038         Scene *scene = CTX_data_scene(C);
2039         SaveImageOptions simopts;
2040
2041         save_image_options_defaults(&simopts);
2042         if (save_image_options_init(&simopts, sima, scene, false, false) == 0)
2043                 return OPERATOR_CANCELLED;
2044         save_image_options_from_op(&simopts, op);
2045
2046         if (BLI_exists(simopts.filepath) && BLI_file_is_writable(simopts.filepath)) {
2047                 if (save_image_doit(C, sima, op, &simopts, false)) {
2048                         /* report since this can be called from key-shortcuts */
2049                         BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", simopts.filepath);
2050                 }
2051         }
2052         else {
2053                 BKE_reportf(op->reports, RPT_ERROR, "Cannot save image, path '%s' is not writable", simopts.filepath);
2054                 return OPERATOR_CANCELLED;
2055         }
2056
2057         return OPERATOR_FINISHED;
2058 }
2059
2060 void IMAGE_OT_save(wmOperatorType *ot)
2061 {
2062         /* identifiers */
2063         ot->name = "Save Image";
2064         ot->idname = "IMAGE_OT_save";
2065         ot->description = "Save the image with current name and settings";
2066         
2067         /* api callbacks */
2068         ot->exec = image_save_exec;
2069         ot->poll = space_image_file_exists_poll;
2070
2071         /* flags */
2072         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2073 }
2074
2075 /******************* save sequence operator ********************/
2076
2077 static int image_save_sequence_exec(bContext *C, wmOperator *op)
2078 {
2079         Main *bmain = CTX_data_main(C);
2080         SpaceImage *sima = CTX_wm_space_image(C);
2081         ImBuf *ibuf, *first_ibuf = NULL;
2082         int tot = 0;
2083         char di[FILE_MAX];
2084         struct MovieCacheIter *iter;
2085         
2086         if (sima->image == NULL)
2087                 return OPERATOR_CANCELLED;
2088
2089         if (sima->image->source != IMA_SRC_SEQUENCE) {
2090                 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2091                 return OPERATOR_CANCELLED;
2092         }
2093
2094         if (sima->image->type == IMA_TYPE_MULTILAYER) {
2095                 BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2096                 return OPERATOR_CANCELLED;
2097         }
2098         
2099         /* get total dirty buffers and first dirty buffer which is used for menu */
2100         ibuf = NULL;
2101         if (sima->image->cache != NULL) {
2102                 iter = IMB_moviecacheIter_new(sima->image->cache);
2103                 while (!IMB_moviecacheIter_done(iter)) {
2104                         ibuf = IMB_moviecacheIter_getImBuf(iter);
2105                         if (ibuf->userflags & IB_BITMAPDIRTY) {
2106                                 if (first_ibuf == NULL) {
2107                                         first_ibuf = ibuf;
2108                                 }
2109                                 tot++;
2110                         }
2111                         IMB_moviecacheIter_step(iter);
2112                 }
2113                 IMB_moviecacheIter_free(iter);
2114         }
2115         
2116         if (tot == 0) {
2117                 BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2118                 return OPERATOR_CANCELLED;
2119         }
2120
2121         /* get a filename for menu */
2122         BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
2123         BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2124
2125         iter = IMB_moviecacheIter_new(sima->image->cache);
2126         while (!IMB_moviecacheIter_done(iter)) {
2127                 ibuf = IMB_moviecacheIter_getImBuf(iter);
2128
2129                 if (ibuf->userflags & IB_BITMAPDIRTY) {
2130                         char name[FILE_MAX];
2131                         BLI_strncpy(name, ibuf->name, sizeof(name));
2132
2133                         BLI_path_abs(name, bmain->name);
2134
2135                         if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
2136                                 BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", name);
2137                                 break;
2138                         }
2139
2140                         BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->name);
2141                         ibuf->userflags &= ~IB_BITMAPDIRTY;
2142                 }
2143
2144                 IMB_moviecacheIter_step(iter);
2145         }
2146         IMB_moviecacheIter_free(iter);
2147
2148         return OPERATOR_FINISHED;
2149 }
2150
2151 void IMAGE_OT_save_sequence(wmOperatorType *ot)
2152 {
2153         /* identifiers */
2154         ot->name = "Save Sequence";
2155         ot->idname = "IMAGE_OT_save_sequence";
2156         ot->description = "Save a sequence of images";
2157         
2158         /* api callbacks */
2159         ot->exec = image_save_sequence_exec;
2160         ot->poll = space_image_buffer_exists_poll;
2161
2162         /* flags */
2163         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2164 }
2165
2166 /******************** reload image operator ********************/
2167
2168 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
2169 {
2170         Image *ima = CTX_data_edit_image(C);
2171         SpaceImage *sima = CTX_wm_space_image(C);
2172
2173         if (!ima)
2174                 return OPERATOR_CANCELLED;
2175
2176         /* XXX unpackImage frees image buffers */
2177         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2178         
2179         // XXX other users?
2180         BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
2181         DAG_id_tag_update(&ima->id, 0);
2182
2183         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2184         
2185         return OPERATOR_FINISHED;
2186 }
2187
2188 void IMAGE_OT_reload(wmOperatorType *ot)
2189 {
2190         /* identifiers */
2191         ot->name = "Reload Image";
2192         ot->idname = "IMAGE_OT_reload";
2193         ot->description = "Reload current image from disk";
2194         
2195         /* api callbacks */
2196         ot->exec = image_reload_exec;
2197
2198         /* flags */
2199         ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2200 }
2201
2202 /********************** new image operator *********************/
2203 #define IMA_DEF_NAME N_("Untitled")
2204
2205 enum {
2206         GEN_CONTEXT_NONE = 0,
2207         GEN_CONTEXT_PAINT_CANVAS = 1,
2208         GEN_CONTEXT_PAINT_STENCIL = 2
2209 };
2210
2211 static int image_new_exec(bContext *C, wmOperator *op)
2212 {
2213         SpaceImage *sima;
2214         Scene *scene;
2215         Object *obedit;
2216         Image *ima;
2217         Main *bmain;
2218         PointerRNA ptr, idptr;
2219         PropertyRNA *prop;
2220         char _name[MAX_ID_NAME - 2];
2221         char *name = _name;
2222         float color[4];
2223         int width, height, floatbuf, gen_type, alpha;
2224         int gen_context;
2225         int stereo3d;
2226
2227         /* retrieve state */
2228         sima = CTX_wm_space_image(C);
2229         scene = CTX_data_scene(C);
2230         obedit = CTX_data_edit_object(C);
2231         bmain = CTX_data_main(C);
2232
2233         prop = RNA_struct_find_property(op->ptr, "name");
2234         RNA_property_string_get(op->ptr, prop, name);
2235         if (!RNA_property_is_set(op->ptr, prop)) {
2236                 /* Default value, we can translate! */
2237                 name = (char *)DATA_(name);
2238         }
2239         width = RNA_int_get(op->ptr, "width");
2240         height = RNA_int_get(op->ptr, "height");
2241         floatbuf = RNA_boolean_get(op->ptr, "float");
2242         gen_type = RNA_enum_get(op->ptr, "generated_type");
2243         RNA_float_get_array(op->ptr, "color", color);
2244         alpha = RNA_boolean_get(op->ptr, "alpha");
2245         gen_context = RNA_enum_get(op->ptr, "gen_context");
2246         stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2247
2248         if (!alpha)
2249                 color[3] = 1.0f;
2250
2251         ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
2252
2253         if (!ima)
2254                 return OPERATOR_CANCELLED;
2255
2256         /* hook into UI */
2257         UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
2258
2259         if (prop) {
2260                 /* when creating new ID blocks, use is already 1, but RNA
2261                  * pointer se also increases user, so this compensates it */
2262                 ima->id.us--;
2263
2264                 RNA_id_pointer_create(&ima->id, &idptr);
2265                 RNA_property_pointer_set(&ptr, prop, idptr);
2266                 RNA_property_update(C, &ptr, prop);
2267         }
2268         else if (sima) {
2269                 ED_space_image_set(sima, scene, obedit, ima);
2270         }
2271         else if (gen_context == GEN_CONTEXT_PAINT_CANVAS) {
2272                 bScreen *sc;
2273                 Object *ob = CTX_data_active_object(C);
2274                 
2275                 GPU_drawobject_free(ob->derivedFinal);  
2276                 if (scene->toolsettings->imapaint.canvas)
2277                         id_us_min(&scene->toolsettings->imapaint.canvas->id);
2278                 scene->toolsettings->imapaint.canvas = ima;
2279                 
2280                 for (sc = bmain->screen.first; sc; sc = sc->id.next) {
2281                         ScrArea *sa;
2282                         for (sa = sc->areabase.first; sa; sa = sa->next) {
2283                                 SpaceLink *sl;
2284                                 for (sl = sa->spacedata.first; sl; sl = sl->next) {
2285                                         if (sl->spacetype == SPACE_IMAGE) {
2286                                                 SpaceImage *sima = (SpaceImage *)sl;
2287                                                 
2288                                                 if (!sima->pin)
2289                                                         ED_space_image_set(sima, scene, scene->obedit, ima);
2290                                         }
2291                                 }
2292                         }
2293                 }
2294                 BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
2295                 WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
2296         }
2297         else if (gen_context == GEN_CONTEXT_PAINT_STENCIL) {
2298                 Object *ob = CTX_data_active_object(C);
2299                 if (scene->toolsettings->imapaint.stencil)
2300                         id_us_min(&scene->toolsettings->imapaint.stencil->id);
2301                 scene->toolsettings->imapaint.stencil = ima;
2302                 BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);      
2303                 WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);             
2304         }
2305         else {
2306                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
2307                 if (tex && tex->type == TEX_IMAGE) {
2308                         if (tex->ima)
2309                                 id_us_min(&tex->ima->id);
2310                         tex->ima = ima;
2311                         ED_area_tag_redraw(CTX_wm_area(C));
2312                 }
2313         }
2314
2315         BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
2316         
2317         WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
2318         
2319         return OPERATOR_FINISHED;
2320 }
2321
2322 /* XXX, Ton is not a fan of OK buttons but using this function to avoid undo/redo bug while in mesh-editmode, - campbell */
2323 /* XXX Note: the WM_operator_props_dialog_popup() doesn't work for UI_context_active_but_prop_get_templateID(), image is not being that way */
2324 static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2325 {
2326         /* Better for user feedback. */
2327         RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2328         return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
2329 }
2330
2331 static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
2332 {
2333         uiLayout *split, *col[2];
2334         uiLayout *layout = op->layout;
2335         PointerRNA ptr;
2336 #if 0
2337         Scene *scene = CTX_data_scene(C);
2338         const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2339 #endif
2340
2341         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2342
2343         /* copy of WM_operator_props_dialog_popup() layout */
2344
2345         split = uiLayoutSplit(layout, 0.5f, false);
2346         col[0] = uiLayoutColumn(split, false);
2347         col[1] = uiLayoutColumn(split, false);
2348
2349         uiItemL(col[0], IFACE_("Name"), ICON_NONE);
2350         uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
2351
2352         uiItemL(col[0], IFACE_("Width"), ICON_NONE);
2353         uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
2354
2355         uiItemL(col[0], IFACE_("Height"), ICON_NONE);
2356         uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
2357
2358         uiItemL(col[0], IFACE_("Color"), ICON_NONE);
2359         uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
2360
2361         uiItemL(col[0], "", ICON_NONE);
2362         uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
2363
2364         uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
2365         uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
2366
2367         uiItemL(col[0], "", ICON_NONE);
2368         uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
2369
2370 #if 0
2371         if (is_multiview) {
2372                 uiItemL(col[0], "", ICON_NONE);
2373                 uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
2374         }
2375 #endif
2376 }
2377
2378 void IMAGE_OT_new(wmOperatorType *ot)
2379 {
2380         PropertyRNA *prop;
2381         static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2382
2383         static EnumPropertyItem gen_context_items[] = {
2384                 {GEN_CONTEXT_NONE, "NONE", 0, "None", ""},
2385                 {GEN_CONTEXT_PAINT_CANVAS, "PAINT_CANVAS", 0, "Paint Canvas", ""},
2386             {GEN_CONTEXT_PAINT_STENCIL, "PAINT_STENCIL", 0, "Paint Stencil", ""},
2387                 {0, NULL, 0, NULL, NULL}
2388         };
2389         
2390         /* identifiers */
2391         ot->name = "New Image";
2392         ot->description = "Create a new image";
2393         ot->idname = "IMAGE_OT_new";
2394         
2395         /* api callbacks */
2396         ot->exec = image_new_exec;
2397         ot->invoke = image_new_invoke;
2398         ot->ui = image_new_draw;
2399         
2400         /* flags */
2401         ot->flag = OPTYPE_UNDO;
2402
2403         /* properties */
2404         RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
2405         prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2406         RNA_def_property_subtype(prop, PROP_PIXEL);
2407         prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2408         RNA_def_property_subtype(prop, PROP_PIXEL);
2409         prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2410         RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
2411         RNA_def_property_float_array_default(prop, default_color);
2412         RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
2413         RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
2414                      "Generated Type", "Fill the image with a grid for UV map testing");
2415         RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
2416         prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
2417         RNA_def_property_flag(prop, PROP_HIDDEN);
2418         prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
2419         RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
2420 }
2421
2422 #undef IMA_DEF_NAME
2423
2424 /********************* invert operators *********************/
2425
2426 static int image_invert_poll(bContext *C)
2427 {
2428         Image *ima = CTX_data_edit_image(C);
2429
2430         return BKE_image_has_ibuf(ima, NULL);
2431 }
2432
2433 static int image_invert_exec(bContext *C, wmOperator *op)
2434 {
2435         Image *ima = CTX_data_edit_image(C);
2436         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2437         SpaceImage *sima = CTX_wm_space_image(C);
2438         /* undo is supported only on image paint mode currently */
2439         bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2440
2441         /* flags indicate if this channel should be inverted */
2442         const bool r = RNA_boolean_get(op->ptr, "invert_r");
2443         const bool g = RNA_boolean_get(op->ptr, "invert_g");
2444         const bool b = RNA_boolean_get(op->ptr, "invert_b");
2445         const bool a = RNA_boolean_get(op->ptr, "invert_a");
2446
2447         int i;
2448
2449         if (ibuf == NULL)  /* TODO: this should actually never happen, but does for render-results -> cleanup */
2450                 return OPERATOR_CANCELLED;
2451
2452         if (support_undo) {
2453                 ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
2454                                          ED_image_undo_restore, ED_image_undo_free, NULL);
2455                 /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
2456                  * but better do this right in case someone copies this for a tool that uses partial redraw better */
2457                 ED_imapaint_clear_partial_redraw();
2458                 ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
2459         }
2460         /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
2461         if (ibuf->rect_float) {
2462                 
2463                 float *fp = (float *) ibuf->rect_float;
2464                 for (i = ibuf->x * ibuf->y; i > 0; i--, fp += 4) {
2465                         if (r) fp[0] = 1.0f - fp[0];
2466                         if (g) fp[1] = 1.0f - fp[1];
2467                         if (b) fp[2] = 1.0f - fp[2];
2468                         if (a) fp[3] = 1.0f - fp[3];
2469                 }
2470
2471                 if (ibuf->rect) {
2472                         IMB_rect_from_float(ibuf);
2473                 }
2474         }
2475         else if (ibuf->rect) {
2476                 
2477                 char *cp = (char *) ibuf->rect;
2478                 for (i = ibuf->x * ibuf->y; i > 0; i--, cp += 4) {
2479                         if (r) cp[0] = 255 - cp[0];
2480                         if (g) cp[1] = 255 - cp[1];
2481                         if (b) cp[2] = 255 - cp[2];
2482                         if (a) cp[3] = 255 - cp[3];
2483                 }
2484         }
2485         else {
2486                 BKE_image_release_ibuf(ima, ibuf, NULL);
2487                 return OPERATOR_CANCELLED;
2488         }
2489
2490         ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;
2491
2492         if (ibuf->mipmap[0])
2493                 ibuf->userflags |= IB_MIPMAP_INVALID;
2494
2495         if (support_undo)
2496                 ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
2497
2498         /* force GPU reupload, all image is invalid */
2499         GPU_free_image(ima);
2500
2501         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2502
2503         BKE_image_release_ibuf(ima, ibuf, NULL);
2504
2505         return OPERATOR_FINISHED;
2506 }
2507
2508 void IMAGE_OT_invert(wmOperatorType *ot)
2509 {
2510         PropertyRNA *prop;
2511
2512         /* identifiers */
2513         ot->name = "Invert Channels";
2514         ot->idname = "IMAGE_OT_invert";
2515         ot->description = "Invert image's channels";
2516         
2517         /* api callbacks */
2518         ot->exec = image_invert_exec;
2519         ot->poll = image_invert_poll;
2520         
2521         /* properties */
2522         prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
2523         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2524         prop = RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel");
2525         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2526         prop = RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel");
2527         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2528         prop = RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel");
2529         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2530         
2531         /* flags */
2532         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2533 }
2534
2535 /********************* pack operator *********************/
2536
2537 static bool image_pack_test(bContext *C, wmOperator *op)
2538 {
2539         Image *ima = CTX_data_edit_image(C);
2540         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2541
2542         if (!ima)
2543                 return 0;
2544         if (!as_png && BKE_image_has_packedfile(ima))
2545                 return 0;
2546
2547         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2548                 BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
2549                 return 0;
2550         }
2551
2552         return 1;
2553 }
2554
2555 static int image_pack_exec(bContext *C, wmOperator *op)
2556 {
2557         struct Main *bmain = CTX_data_main(C);
2558         Image *ima = CTX_data_edit_image(C);
2559         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2560         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2561
2562         if (!image_pack_test(C, op))
2563                 return OPERATOR_CANCELLED;
2564         
2565         if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
2566                 BKE_report(op->reports, RPT_ERROR, "Cannot pack edited image from disk, only as internal PNG");
2567                 return OPERATOR_CANCELLED;
2568         }
2569
2570         if (as_png)
2571                 BKE_image_memorypack(ima);
2572         else
2573                 BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
2574
2575         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2576
2577         BKE_image_release_ibuf(ima, ibuf, NULL);
2578
2579         return OPERATOR_FINISHED;
2580 }
2581
2582 static int image_pack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2583 {
2584         Image *ima = CTX_data_edit_image(C);
2585         ImBuf *ibuf;
2586         uiPopupMenu *pup;
2587         uiLayout *layout;
2588         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2589
2590         if (!image_pack_test(C, op))
2591                 return OPERATOR_CANCELLED;
2592
2593         ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2594
2595         if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
2596                 pup = UI_popup_menu_begin(C, IFACE_("OK"), ICON_QUESTION);
2597                 layout = UI_popup_menu_layout(pup);
2598                 uiItemBooleanO(layout, IFACE_("Can't pack edited image from disk, pack as internal PNG?"), ICON_NONE,
2599                                op->idname, "as_png", 1);
2600                 UI_popup_menu_end(C, pup);
2601
2602                 BKE_image_release_ibuf(ima, ibuf, NULL);
2603
2604                 return OPERATOR_INTERFACE;
2605         }
2606
2607         BKE_image_release_ibuf(ima, ibuf, NULL);
2608
2609         return image_pack_exec(C, op);
2610 }
2611
2612 void IMAGE_OT_pack(wmOperatorType *ot)
2613 {
2614         /* identifiers */
2615         ot->name = "Pack Image";
2616         ot->description = "Pack an image as embedded data into the .blend file"; 
2617         ot->idname = "IMAGE_OT_pack";
2618         
2619         /* api callbacks */
2620         ot->exec = image_pack_exec;
2621         ot->invoke = image_pack_invoke;
2622
2623         /* flags */
2624         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2625
2626         /* properties */
2627         RNA_def_boolean(ot->srna, "as_png", 0, "Pack As PNG", "Pack image as lossless PNG");
2628 }
2629
2630 /********************* unpack operator *********************/
2631
2632 static int image_unpack_exec(bContext *C, wmOperator *op)
2633 {
2634         Image *ima = CTX_data_edit_image(C);
2635         int method = RNA_enum_get(op->ptr, "method");
2636
2637         /* find the suppplied image by name */
2638         if (RNA_struct_property_is_set(op->ptr, "id")) {
2639                 char imaname[MAX_ID_NAME - 2];
2640                 RNA_string_get(op->ptr, "id", imaname);
2641                 ima = BLI_findstring(&CTX_data_main(C)->image, imaname, offsetof(ID, name) + 2);
2642                 if (!ima) ima = CTX_data_edit_image(C);
2643         }
2644         
2645         if (!ima || !BKE_image_has_packedfile(ima))
2646                 return OPERATOR_CANCELLED;
2647
2648         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2649                 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2650                 return OPERATOR_CANCELLED;
2651         }
2652
2653         if (G.fileflags & G_AUTOPACK)
2654                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
2655         
2656         /* XXX unpackImage frees image buffers */
2657         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2658         
2659         unpackImage(op->reports, ima, method);
2660         
2661         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2662
2663         return OPERATOR_FINISHED;
2664 }
2665
2666 static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2667 {
2668         Image *ima = CTX_data_edit_image(C);
2669
2670         if (RNA_struct_property_is_set(op->ptr, "id"))
2671                 return image_unpack_exec(C, op);
2672                 
2673         if (!ima || !BKE_image_has_packedfile(ima))
2674                 return OPERATOR_CANCELLED;
2675
2676         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2677                 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2678                 return OPERATOR_CANCELLED;
2679         }
2680
2681         if (G.fileflags & G_AUTOPACK)
2682                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
2683
2684         unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", BKE_image_has_packedfile(ima) ? ((ImagePackedFile *)ima->packedfiles.first)->packedfile : NULL);
2685
2686         return OPERATOR_FINISHED;
2687 }
2688
2689 void IMAGE_OT_unpack(wmOperatorType *ot)
2690 {
2691         /* identifiers */
2692         ot->name = "Unpack Image";
2693         ot->description = "Save an image packed in the .blend file to disk"; 
2694         ot->idname = "IMAGE_OT_unpack";
2695         
2696         /* api callbacks */
2697         ot->exec = image_unpack_exec;
2698         ot->invoke = image_unpack_invoke;
2699
2700         /* flags */
2701         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2702         
2703         /* properties */
2704         RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
2705         RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
2706 }
2707
2708 /******************** sample image operator ********************/
2709
2710 typedef struct ImageSampleInfo {
2711         ARegionType *art;
2712         void *draw_handle;
2713         int x, y;
2714         int channels;
2715
2716         unsigned char col[4];
2717         float colf[4];
2718         float linearcol[4];
2719         int z;
2720         float zf;
2721
2722         unsigned char *colp;
2723         const float *colfp;
2724         int *zp;
2725         float *zfp;
2726
2727         int draw;
2728         int color_manage;
2729         int use_default_view;
2730 } ImageSampleInfo;
2731
2732 static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
2733 {
2734         ImageSampleInfo *info = arg_info;
2735         if (info->draw) {
2736                 Scene *scene = CTX_data_scene(C);
2737
2738                 ED_image_draw_info(scene, ar, info->color_manage, info->use_default_view, info->channels,
2739                                    info->x, info->y, info->colp, info->colfp, info->linearcol, info->zp, info->zfp);
2740         }
2741 }
2742
2743 /* Returns color in the display space, matching ED_space_node_color_sample(). */
2744 bool ED_space_image_color_sample(Scene *scene, SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
2745 {
2746         const char *display_device = scene->display_settings.display_device;
2747         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
2748         void *lock;
2749         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2750         float fx, fy;
2751         bool ret = false;
2752
2753         if (ibuf == NULL) {
2754                 ED_space_image_release_buffer(sima, ibuf, lock);
2755                 return false;
2756         }
2757
2758         UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
2759
2760         if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2761                 const float *fp;
2762                 unsigned char *cp;
2763                 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2764
2765                 CLAMP(x, 0, ibuf->x - 1);
2766                 CLAMP(y, 0, ibuf->y - 1);
2767
2768                 if (ibuf->rect_float) {
2769                         fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
2770                         copy_v3_v3(r_col, fp);
2771                         ret = true;
2772                 }
2773                 else if (ibuf->rect) {
2774                         cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
2775                         rgb_uchar_to_float(r_col, cp);
2776                         IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
2777                         ret = true;
2778                 }
2779         }
2780
2781         if (ret) {
2782                 IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
2783         }
2784
2785         ED_space_image_release_buffer(sima, ibuf, lock);
2786         return ret;
2787 }
2788
2789 static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
2790 {
2791         SpaceImage *sima = CTX_wm_space_image(C);
2792         ARegion *ar = CTX_wm_region(C);
2793         void *lock;
2794         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2795         ImageSampleInfo *info = op->customdata;
2796         float fx, fy;
2797         Scene *scene = CTX_data_scene(C);
2798         CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
2799
2800         if (ibuf == NULL) {
2801                 ED_space_image_release_buffer(sima, ibuf, lock);
2802                 info->draw = 0;
2803                 return;
2804         }
2805
2806         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
2807
2808         if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2809                 const float *fp;
2810                 unsigned char *cp;
2811                 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2812                 Image *image = ED_space_image(sima);
2813
2814                 CLAMP(x, 0, ibuf->x - 1);
2815                 CLAMP(y, 0, ibuf->y - 1);
2816
2817                 info->x = x;
2818                 info->y = y;
2819                 info->draw = 1;
2820                 info->channels = ibuf->channels;
2821
2822                 info->colp = NULL;
2823                 info->colfp = NULL;
2824                 info->zp = NULL;
2825                 info->zfp = NULL;
2826
2827                 info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
2828
2829                 if (ibuf->rect) {
2830                         cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
2831
2832                         info->col[0] = cp[0];
2833                         info->col[1] = cp[1];
2834                         info->col[2] = cp[2];
2835                         info->col[3] = cp[3];
2836                         info->colp = info->col;
2837
2838                         info->colf[0] = (float)cp[0] / 255.0f;
2839                         info->colf[1] = (float)cp[1] / 255.0f;
2840                         info->colf[2] = (float)cp[2] / 255.0f;
2841                         info->colf[3] = (float)cp[3] / 255.0f;
2842                         info->colfp = info->colf;
2843
2844                         copy_v4_v4(info->linearcol, info->colf);
2845                         IMB_colormanagement_colorspace_to_scene_linear_v4(info->linearcol, false, ibuf->rect_colorspace);
2846
2847                         info->color_manage = true;
2848                 }
2849                 if (ibuf->rect_float) {
2850                         fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
2851
2852                         info->colf[0] = fp[0];
2853                         info->colf[1] = fp[1];
2854                         info->colf[2] = fp[2];
2855                         info->colf[3] = fp[3];
2856                         info->colfp = info->colf;
2857
2858                         copy_v4_v4(info->linearcol, info->colf);
2859
2860                         info->color_manage = true;
2861                 }
2862
2863                 if (ibuf->zbuf) {
2864                         info->z = ibuf->zbuf[y * ibuf->x + x];
2865                         info->zp = &info->z;
2866                 }
2867                 if (ibuf->zbuf_float) {
2868                         info->zf = ibuf->zbuf_float[y * ibuf->x + x];
2869                         info->zfp = &info->zf;
2870                 }
2871
2872                 if (curve_mapping && ibuf->channels == 4) {
2873                         /* we reuse this callback for set curves point operators */
2874                         if (RNA_struct_find_property(op->ptr, "point")) {
2875                                 int point = RNA_enum_get(op->ptr, "point");
2876
2877                                 if (point == 1) {
2878                                         curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
2879                                 }
2880                                 else if (point == 0) {
2881                                         curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
2882                                 }
2883                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
2884                         }
2885                 }
2886
2887                 // XXX node curve integration ..
2888 #if 0
2889                 {
2890                         ScrArea *sa, *cur = curarea;
2891                         
2892                         node_curvemap_sample(fp);   /* sends global to node editor */
2893                         for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
2894                                 if (sa->spacetype == SPACE_NODE) {
2895                                         areawinset(sa->win);
2896                                         scrarea_do_windraw(sa);
2897                                 }
2898                         }
2899                         node_curvemap_sample(NULL);     /* clears global in node editor */
2900                         curarea = cur;
2901                 }
2902 #endif
2903         }
2904         else {
2905                 info->draw = 0;
2906         }
2907
2908         ED_space_image_release_buffer(sima, ibuf, lock);
2909         ED_area_tag_redraw(CTX_wm_area(C));
2910 }
2911
2912 static void image_sample_exit(bContext *C, wmOperator *op)
2913 {
2914         ImageSampleInfo *info = op->customdata;
2915
2916         ED_region_draw_cb_exit(info->art, info->draw_handle);
2917         ED_area_tag_redraw(CTX_wm_area(C));
2918         MEM_freeN(info);
2919 }
2920
2921 static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2922 {
2923         SpaceImage *sima = CTX_wm_space_image(C);
2924         ARegion *ar = CTX_wm_region(C);
2925         ImageSampleInfo *info;
2926
2927         if (ar->regiontype == RGN_TYPE_WINDOW) {
2928                 if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
2929                         return OPERATOR_PASS_THROUGH;
2930                 }
2931         }
2932
2933         if (!ED_space_image_has_buffer(sima))
2934                 return OPERATOR_CANCELLED;
2935         
2936         info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
2937         info->art = ar->type;
2938         info->draw_handle = ED_region_draw_cb_activate(ar->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
2939         op->customdata = info;
2940
2941         image_sample_apply(C, op, event);
2942
2943         WM_event_add_modal_handler(C, op);
2944
2945         return OPERATOR_RUNNING_MODAL;
2946 }
2947
2948 static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
2949 {
2950         switch (event->type) {
2951                 case LEFTMOUSE:
2952                 case RIGHTMOUSE: // XXX hardcoded
2953                 if (event->val == KM_RELEASE) {
2954                         image_sample_exit(C, op);
2955                         return OPERATOR_CANCELLED;
2956                 }
2957                 break;
2958                 case MOUSEMOVE:
2959                         image_sample_apply(C, op, event);
2960                         break;
2961         }
2962
2963         return OPERATOR_RUNNING_MODAL;
2964 }
2965
2966 static void image_sample_cancel(bContext *C, wmOperator *op)
2967 {
2968         image_sample_exit(C, op);
2969 }
2970
2971 void IMAGE_OT_sample(wmOperatorType *ot)
2972 {
2973         /* identifiers */
2974         ot->name = "Sample Color";
2975         ot->idname = "IMAGE_OT_sample";
2976         ot->description = "Use mouse to sample a color in current image";
2977         
2978         /* api callbacks */
2979         ot->invoke = image_sample_invoke;
2980         ot->modal = image_sample_modal;
2981         ot->cancel = image_sample_cancel;
2982         ot->poll = image_sample_poll;
2983
2984         /* flags */
2985         ot->flag = OPTYPE_BLOCKING;
2986 }
2987
2988 /******************** sample line operator ********************/
2989 static int image_sample_line_exec(bContext *C, wmOperator *op)
2990 {
2991         SpaceImage *sima = CTX_wm_space_image(C);
2992         ARegion *ar = CTX_wm_region(C);
2993         Scene *scene = CTX_data_scene(C);
2994
2995         int x_start = RNA_int_get(op->ptr, "xstart");
2996         int y_start = RNA_int_get(op->ptr, "ystart");
2997         int x_end = RNA_int_get(op->ptr, "xend");
2998         int y_end = RNA_int_get(op->ptr, "yend");
2999         
3000         void *lock;
3001         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
3002         Histogram *hist = &sima->sample_line_hist;
3003         
3004         float x1f, y1f, x2f, y2f;
3005         
3006         if (ibuf == NULL) {
3007                 ED_space_image_release_buffer(sima, ibuf, lock);
3008                 return OPERATOR_CANCELLED;
3009         }
3010         /* hmmmm */
3011         if (ibuf->channels < 3) {
3012                 ED_space_image_release_buffer(sima, ibuf, lock);
3013                 return OPERATOR_CANCELLED;
3014         }
3015         
3016         UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
3017         UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
3018
3019         hist->co[0][0] = x1f;
3020         hist->co[0][1] = y1f;
3021         hist->co[1][0] = x2f;
3022         hist->co[1][1] = y2f;
3023
3024         /* enable line drawing */
3025         hist->flag |= HISTO_FLAG_SAMPLELINE;
3026
3027         BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
3028         
3029         /* reset y zoom */
3030         hist->ymax = 1.0f;
3031
3032         ED_space_image_release_buffer(sima, ibuf, lock);
3033         
3034         ED_area_tag_redraw(CTX_wm_area(C));
3035         
3036         return OPERATOR_FINISHED;
3037 }
3038
3039 static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3040 {
3041         SpaceImage *sima = CTX_wm_space_image(C);
3042
3043         Histogram *hist = &sima->sample_line_hist;
3044         hist->flag &= ~HISTO_FLAG_SAMPLELINE;
3045
3046         if (!ED_space_image_has_buffer(sima))
3047                 return OPERATOR_CANCELLED;
3048         
3049         return WM_gesture_straightline_invoke(C, op, event);
3050 }
3051
3052 void IMAGE_OT_sample_line(wmOperatorType *ot)
3053 {
3054         /* identifiers */
3055         ot->name = "Sample Line";
3056         ot->idname = "IMAGE_OT_sample_line";
3057         ot->description = "Sample a line and show it in Scope panels";
3058         
3059         /* api callbacks */
3060         ot->invoke = image_sample_line_invoke;
3061         ot->modal = WM_gesture_straightline_modal;
3062         ot->exec = image_sample_line_exec;
3063         ot->poll = space_image_main_area_poll;
3064         ot->cancel = WM_gesture_straightline_cancel;
3065         
3066         /* flags */
3067         ot->flag = 0; /* no undo/register since this operates on the space */
3068         
3069         WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
3070 }
3071
3072 /******************** set curve point operator ********************/
3073
3074 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
3075 {
3076         static EnumPropertyItem point_items[] = {
3077                 {0, "BLACK_POINT", 0, "Black Point", ""},
3078                 {1, "WHITE_POINT", 0, "White Point", ""},
3079                 {0, NULL, 0, NULL, NULL}
3080         };
3081
3082         /* identifiers */
3083         ot->name = "Set Curves Point";
3084         ot->idname = "IMAGE_OT_curves_point_set";
3085         ot->description = "Set black point or white point for curves";
3086
3087         /* flags */
3088         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3089         
3090         /* api callbacks */
3091         ot->invoke = image_sample_invoke;
3092         ot->modal = image_sample_modal;
3093         ot->cancel = image_sample_cancel;
3094         ot->poll = space_image_main_area_not_uv_brush_poll;
3095
3096         /* properties */
3097         RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3098 }
3099
3100 #if 0 /* Not ported to 2.5x yet */
3101 /******************** record composite operator *********************/
3102
3103 typedef struct RecordCompositeData {
3104         wmTimer *timer;
3105         int old_cfra;
3106         int sfra, efra;
3107 } RecordCompositeData;
3108
3109 static int image_record_composite_apply(bContext *C, wmOperator *op)
3110 {
3111         SpaceImage *sima = CTX_wm_space_image(C);
3112         RecordCompositeData *rcd = op->customdata;
3113         Scene *scene = CTX_data_scene(C);
3114         ImBuf *ibuf;
3115         
3116         WM_cursor_time(CTX_wm_window(C), scene->r.cfra);
3117
3118         // XXX scene->nodetree->test_break = blender_test_break;
3119         // XXX scene->nodetree->test_break = NULL;
3120         
3121         BKE_image_all_free_anim_ibufs(scene->r.cfra);
3122         ntreeCompositTagAnimated(scene->nodetree);
3123         ntreeCompositExecTree(scene->nodetree, &scene->r, 0, scene->r.cfra != rcd->old_cfra,
3124                               &scene->view_settings, &scene->display_settings);  /* 1 is no previews */
3125
3126         ED_area_tag_redraw(CTX_wm_area(C));
3127         
3128         ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, NULL);
3129         /* save memory in flipbooks */
3130         if (ibuf)
3131                 imb_freerectfloatImBuf(ibuf);
3132
3133         BKE_image_release_ibuf(sima->image, ibuf, NULL);
3134
3135         scene->r.cfra++;
3136
3137         return (scene->r.cfra <= rcd->efra);
3138 }
3139
3140 static int image_record_composite_init(bContext *C, wmOperator *op)
3141 {
3142         SpaceImage *sima = CTX_wm_space_image(C);
3143         Scene *scene = CTX_data_scene(C);
3144         RecordCompositeData *rcd;
3145
3146         if (sima->iuser.frames < 2)
3147                 return 0;
3148         if (scene->nodetree == NULL)
3149                 return 0;
3150         
3151         op->customdata = rcd = MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData");
3152
3153         rcd->old_cfra = scene->r.cfra;
3154         rcd->sfra = sima->iuser.sfra;
3155         rcd->efra = sima->iuser.sfra + sima->iuser.frames - 1;
3156         scene->r.cfra = rcd->sfra;
3157
3158         return 1;
3159 }
3160
3161 static void image_record_composite_exit(bContext *C, wmOperator *op)
3162 {
3163         Scene *scene = CTX_data_scene(C);
3164         SpaceImage *sima = CTX_wm_space_image(C);
3165         RecordCompositeData *rcd = op->customdata;
3166
3167         scene->r.cfra = rcd->old_cfra;
3168
3169         WM_cursor_modal_restore(CTX_wm_window(C));
3170
3171         if (rcd->timer)
3172                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer);
3173
3174         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
3175
3176         // XXX play_anim(0);
3177         // XXX allqueue(REDRAWNODE, 1);
3178
3179         MEM_freeN(rcd);
3180 }
3181
3182 static int image_record_composite_exec(bContext *C, wmOperator *op)
3183 {
3184         if (!image_record_composite_init(C, op))
3185                 return OPERATOR_CANCELLED;
3186         
3187         while (image_record_composite_apply(C, op)) {}
3188         
3189         image_record_composite_exit(C, op);
3190         
3191         return OPERATOR_FINISHED;
3192 }
3193
3194 static int image_record_composite_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
3195 {
3196         RecordCompositeData *rcd;