build options to disable image formats WITH_CINEON, WITH_HDR.
[blender.git] / source / blender / editors / space_image / image_ops.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2002-2009, Xavier Thomas
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stddef.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_object_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_packedFile_types.h"
38 #include "DNA_scene_types.h"
39
40 #include "BKE_colortools.h"
41 #include "BKE_context.h"
42 #include "BKE_image.h"
43 #include "BKE_global.h"
44 #include "BKE_image.h"
45 #include "BKE_library.h"
46 #include "BKE_main.h"
47 #include "BKE_node.h"
48 #include "BKE_packedFile.h"
49 #include "BKE_report.h"
50 #include "BKE_screen.h"
51
52 #include "BLI_math.h"
53 #include "BLI_blenlib.h"
54
55 #include "IMB_imbuf.h"
56 #include "IMB_imbuf_types.h"
57
58 #include "RE_pipeline.h"
59
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62 #include "RNA_enum_types.h"
63
64 #include "ED_image.h"
65 #include "ED_screen.h"
66 #include "ED_space_api.h"
67 #include "ED_uvedit.h"
68
69 #include "UI_interface.h"
70 #include "UI_resources.h"
71 #include "UI_view2d.h"
72
73 #include "WM_api.h"
74 #include "WM_types.h"
75
76 #include "image_intern.h"
77
78 /******************** view navigation utilities *********************/
79
80 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom)
81 {
82         float oldzoom= sima->zoom;
83         int width, height;
84
85         sima->zoom= zoom;
86
87         if (sima->zoom > 0.1f && sima->zoom < 4.0f)
88                 return;
89
90         /* check zoom limits */
91         ED_space_image_size(sima, &width, &height);
92
93         width *= sima->zoom;
94         height *= sima->zoom;
95
96         if((width < 4) && (height < 4))
97                 sima->zoom= oldzoom;
98         else if((ar->winrct.xmax - ar->winrct.xmin) <= sima->zoom)
99                 sima->zoom= oldzoom;
100         else if((ar->winrct.ymax - ar->winrct.ymin) <= sima->zoom)
101                 sima->zoom= oldzoom;
102 }
103
104 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac)
105 {
106         sima_zoom_set(sima, ar, sima->zoom*zoomfac);
107 }
108
109 #if 0 // currently unused
110 static int image_poll(bContext *C)
111 {
112         return (CTX_data_edit_image(C) != NULL);
113 }
114 #endif
115
116 static int space_image_buffer_exists_poll(bContext *C)
117 {
118         SpaceImage *sima= CTX_wm_space_image(C);
119         if(sima && sima->spacetype==SPACE_IMAGE)
120                 if(ED_space_image_has_buffer(sima))
121                         return 1;
122         return 0;
123 }
124
125 static int space_image_file_exists_poll(bContext *C)
126 {
127         if(space_image_buffer_exists_poll(C)) {
128                 SpaceImage *sima= CTX_wm_space_image(C);
129                 ImBuf *ibuf;
130                 void *lock;
131                 int poll= 0;
132                 char name[FILE_MAX];
133
134                 ibuf= ED_space_image_acquire_buffer(sima, &lock);
135                 if(ibuf) {
136                         BLI_strncpy(name, ibuf->name, FILE_MAX);
137                         BLI_path_abs(name, G.sce);
138                         poll= (BLI_exists(name) && BLI_is_writable(name));
139                 }
140                 ED_space_image_release_buffer(sima, lock);
141
142                 return poll;
143         }
144         return 0;
145 }
146
147 static int space_image_poll(bContext *C)
148 {
149         SpaceImage *sima= CTX_wm_space_image(C);
150         if(sima && sima->spacetype==SPACE_IMAGE && sima->image)
151                 return 1;
152         return 0;
153 }
154
155 int space_image_main_area_poll(bContext *C)
156 {
157         SpaceImage *sima= CTX_wm_space_image(C);
158         // XXX ARegion *ar= CTX_wm_region(C);
159
160         if(sima)
161                 return 1; // XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW);
162         
163         return 0;
164 }
165
166 /********************** view pan operator *********************/
167
168 typedef struct ViewPanData {
169         float x, y;
170         float xof, yof;
171 } ViewPanData;
172
173 static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
174 {
175         SpaceImage *sima= CTX_wm_space_image(C);
176         ViewPanData *vpd;
177
178         op->customdata= vpd= MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
179         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
180
181         vpd->x= event->x;
182         vpd->y= event->y;
183         vpd->xof= sima->xof;
184         vpd->yof= sima->yof;
185
186         WM_event_add_modal_handler(C, op);
187 }
188
189 static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
190 {
191         SpaceImage *sima= CTX_wm_space_image(C);
192         ViewPanData *vpd= op->customdata;
193
194         if(cancel) {
195                 sima->xof= vpd->xof;
196                 sima->yof= vpd->yof;
197                 ED_region_tag_redraw(CTX_wm_region(C));
198         }
199
200         WM_cursor_restore(CTX_wm_window(C));
201         MEM_freeN(op->customdata);
202 }
203
204 static int view_pan_exec(bContext *C, wmOperator *op)
205 {
206         SpaceImage *sima= CTX_wm_space_image(C);
207         float offset[2];
208
209         RNA_float_get_array(op->ptr, "offset", offset);
210         sima->xof += offset[0];
211         sima->yof += offset[1];
212
213         ED_region_tag_redraw(CTX_wm_region(C));
214
215         /* XXX notifier? */
216 #if 0
217         if(image_preview_active(curarea, NULL, NULL)) {
218                 /* recalculates new preview rect */
219                 scrarea_do_windraw(curarea);
220                 image_preview_event(2);
221         }
222 #endif
223         
224         return OPERATOR_FINISHED;
225 }
226
227 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
228 {
229         if (event->type == MOUSEPAN) {
230                 SpaceImage *sima= CTX_wm_space_image(C);
231                 float offset[2];
232                 
233                 offset[0]= (event->x - event->prevx)/sima->zoom;
234                 offset[1]= (event->y - event->prevy)/sima->zoom;
235                 RNA_float_set_array(op->ptr, "offset", offset);
236
237                 view_pan_exec(C, op);
238                 return OPERATOR_FINISHED;
239         }
240         else {
241                 view_pan_init(C, op, event);
242                 return OPERATOR_RUNNING_MODAL;
243         }
244 }
245
246 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
247 {
248         SpaceImage *sima= CTX_wm_space_image(C);
249         ViewPanData *vpd= op->customdata;
250         float offset[2];
251
252         switch(event->type) {
253                 case MOUSEMOVE:
254                         sima->xof= vpd->xof;
255                         sima->yof= vpd->yof;
256                         offset[0]= (vpd->x - event->x)/sima->zoom;
257                         offset[1]= (vpd->y - event->y)/sima->zoom;
258                         RNA_float_set_array(op->ptr, "offset", offset);
259                         view_pan_exec(C, op);
260                         break;
261                 case MIDDLEMOUSE:
262                 case LEFTMOUSE:
263                         if(event->val==KM_RELEASE) {
264                                 view_pan_exit(C, op, 0);
265                                 return OPERATOR_FINISHED;
266                         }
267                         break;
268         }
269
270         return OPERATOR_RUNNING_MODAL;
271 }
272
273 static int view_pan_cancel(bContext *C, wmOperator *op)
274 {
275         view_pan_exit(C, op, 1);
276         return OPERATOR_CANCELLED;
277 }
278
279 void IMAGE_OT_view_pan(wmOperatorType *ot)
280 {
281         /* identifiers */
282         ot->name= "View Pan";
283         ot->idname= "IMAGE_OT_view_pan";
284         
285         /* api callbacks */
286         ot->exec= view_pan_exec;
287         ot->invoke= view_pan_invoke;
288         ot->modal= view_pan_modal;
289         ot->cancel= view_pan_cancel;
290         ot->poll= space_image_main_area_poll;
291
292         /* flags */
293         ot->flag= OPTYPE_BLOCKING;
294         
295         /* properties */
296         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
297                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
298 }
299
300 /********************** view zoom operator *********************/
301
302 typedef struct ViewZoomData {
303         float x, y;
304         float zoom;
305 } ViewZoomData;
306
307 static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
308 {
309         SpaceImage *sima= CTX_wm_space_image(C);
310         ViewZoomData *vpd;
311
312         op->customdata= vpd= MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
313         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
314
315         vpd->x= event->x;
316         vpd->y= event->y;
317         vpd->zoom= sima->zoom;
318
319         WM_event_add_modal_handler(C, op);
320 }
321
322 static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
323 {
324         SpaceImage *sima= CTX_wm_space_image(C);
325         ViewZoomData *vpd= op->customdata;
326
327         if(cancel) {
328                 sima->zoom= vpd->zoom;
329                 ED_region_tag_redraw(CTX_wm_region(C));
330         }
331
332         WM_cursor_restore(CTX_wm_window(C));
333         MEM_freeN(op->customdata);
334 }
335
336 static int view_zoom_exec(bContext *C, wmOperator *op)
337 {
338         SpaceImage *sima= CTX_wm_space_image(C);
339         ARegion *ar= CTX_wm_region(C);
340
341         sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"));
342
343         ED_region_tag_redraw(CTX_wm_region(C));
344
345         /* XXX notifier? */
346 #if 0
347         if(image_preview_active(curarea, NULL, NULL)) {
348                 /* recalculates new preview rect */
349                 scrarea_do_windraw(curarea);
350                 image_preview_event(2);
351         }
352 #endif
353         
354         return OPERATOR_FINISHED;
355 }
356
357 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
358 {
359         if (event->type == MOUSEZOOM) {
360                 SpaceImage *sima= CTX_wm_space_image(C);
361                 ARegion *ar= CTX_wm_region(C);
362                 float factor;
363                 
364                 factor= 1.0 + (event->x-event->prevx+event->y-event->prevy)/300.0f;
365                 RNA_float_set(op->ptr, "factor", factor);
366                 sima_zoom_set(sima, ar, sima->zoom*factor);
367                 ED_region_tag_redraw(CTX_wm_region(C));
368                 
369                 return OPERATOR_FINISHED;
370         }
371         else {
372                 view_zoom_init(C, op, event);
373                 return OPERATOR_RUNNING_MODAL;
374         }
375 }
376
377 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
378 {
379         SpaceImage *sima= CTX_wm_space_image(C);
380         ARegion *ar= CTX_wm_region(C);
381         ViewZoomData *vpd= op->customdata;
382         float factor;
383
384         switch(event->type) {
385                 case MOUSEMOVE:
386                         factor= 1.0 + (vpd->x-event->x+vpd->y-event->y)/300.0f;
387                         RNA_float_set(op->ptr, "factor", factor);
388                         sima_zoom_set(sima, ar, vpd->zoom*factor);
389                         ED_region_tag_redraw(CTX_wm_region(C));
390                         break;
391                 case MIDDLEMOUSE:
392                 case LEFTMOUSE:
393                         if(event->val==KM_RELEASE) {
394                                 view_zoom_exit(C, op, 0);
395                                 return OPERATOR_FINISHED;
396                         }
397                         break;
398         }
399
400         return OPERATOR_RUNNING_MODAL;
401 }
402
403 static int view_zoom_cancel(bContext *C, wmOperator *op)
404 {
405         view_zoom_exit(C, op, 1);
406         return OPERATOR_CANCELLED;
407 }
408
409 void IMAGE_OT_view_zoom(wmOperatorType *ot)
410 {
411         /* identifiers */
412         ot->name= "View Zoom";
413         ot->idname= "IMAGE_OT_view_zoom";
414         
415         /* api callbacks */
416         ot->exec= view_zoom_exec;
417         ot->invoke= view_zoom_invoke;
418         ot->modal= view_zoom_modal;
419         ot->cancel= view_zoom_cancel;
420         ot->poll= space_image_main_area_poll;
421
422         /* flags */
423         ot->flag= OPTYPE_BLOCKING;
424         
425         /* properties */
426         RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX,
427                 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.", -FLT_MAX, FLT_MAX);
428 }
429
430 /********************** view all operator *********************/
431
432 /* Updates the fields of the View2D member of the SpaceImage struct.
433  * Default behavior is to reset the position of the image and set the zoom to 1
434  * If the image will not fit within the window rectangle, the zoom is adjusted */
435
436 static int view_all_exec(bContext *C, wmOperator *op)
437 {
438         SpaceImage *sima;
439         ARegion *ar;
440         Scene *scene;
441         Object *obedit;
442         float aspx, aspy, zoomx, zoomy, w, h;
443         int width, height;
444
445         /* retrieve state */
446         sima= CTX_wm_space_image(C);
447         ar= CTX_wm_region(C);
448         scene= (Scene*)CTX_data_scene(C);
449         obedit= CTX_data_edit_object(C);
450
451         ED_space_image_size(sima, &width, &height);
452         ED_space_image_aspect(sima, &aspx, &aspy);
453
454         w= width*aspx;
455         h= height*aspy;
456         
457         /* check if the image will fit in the image with zoom==1 */
458         width = ar->winrct.xmax - ar->winrct.xmin + 1;
459         height = ar->winrct.ymax - ar->winrct.ymin + 1;
460
461         if((w >= width || h >= height) && (width > 0 && height > 0)) {
462                 /* find the zoom value that will fit the image in the image space */
463                 zoomx= width/w;
464                 zoomy= height/h;
465                 sima_zoom_set(sima, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy)));
466         }
467         else
468                 sima_zoom_set(sima, ar, 1.0f);
469
470         sima->xof= sima->yof= 0.0f;
471
472         ED_region_tag_redraw(CTX_wm_region(C));
473         
474         return OPERATOR_FINISHED;
475 }
476
477 void IMAGE_OT_view_all(wmOperatorType *ot)
478 {
479         /* identifiers */
480         ot->name= "View All";
481         ot->idname= "IMAGE_OT_view_all";
482         
483         /* api callbacks */
484         ot->exec= view_all_exec;
485         ot->poll= space_image_main_area_poll;
486 }
487
488 /********************** view selected operator *********************/
489
490 static int view_selected_exec(bContext *C, wmOperator *op)
491 {
492         SpaceImage *sima;
493         ARegion *ar;
494         Scene *scene;
495         Object *obedit;
496         Image *ima;
497         float size, min[2], max[2], d[2];
498         int width, height;
499
500         /* retrieve state */
501         sima= CTX_wm_space_image(C);
502         ar= CTX_wm_region(C);
503         scene= (Scene*)CTX_data_scene(C);
504         obedit= CTX_data_edit_object(C);
505
506         ima= ED_space_image(sima);
507         ED_space_image_size(sima, &width, &height);
508
509         /* get bounds */
510         if(!ED_uvedit_minmax(scene, ima, obedit, min, max))
511                 return OPERATOR_CANCELLED;
512
513         /* adjust offset and zoom */
514         sima->xof= (int)(((min[0] + max[0])*0.5f - 0.5f)*width);
515         sima->yof= (int)(((min[1] + max[1])*0.5f - 0.5f)*height);
516
517         d[0]= max[0] - min[0];
518         d[1]= max[1] - min[1];
519         size= 0.5*MAX2(d[0], d[1])*MAX2(width, height)/256.0f;
520         
521         if(size<=0.01) size= 0.01;
522         sima_zoom_set(sima, ar, 0.7/size);
523
524         ED_region_tag_redraw(CTX_wm_region(C));
525         
526         return OPERATOR_FINISHED;
527 }
528
529 static int view_selected_poll(bContext *C)
530 {
531         return (space_image_main_area_poll(C) && ED_operator_uvedit(C));
532 }
533
534 void IMAGE_OT_view_selected(wmOperatorType *ot)
535 {
536         /* identifiers */
537         ot->name= "View Center";
538         ot->idname= "IMAGE_OT_view_selected";
539         
540         /* api callbacks */
541         ot->exec= view_selected_exec;
542         ot->poll= view_selected_poll;
543 }
544
545 /********************** view zoom in/out operator *********************/
546
547 static int view_zoom_in_exec(bContext *C, wmOperator *op)
548 {
549         SpaceImage *sima= CTX_wm_space_image(C);
550         ARegion *ar= CTX_wm_region(C);
551
552         sima_zoom_set_factor(sima, ar, 1.25f);
553
554         ED_region_tag_redraw(CTX_wm_region(C));
555         
556         return OPERATOR_FINISHED;
557 }
558
559 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
560 {
561         /* identifiers */
562         ot->name= "View Zoom In";
563         ot->idname= "IMAGE_OT_view_zoom_in";
564         
565         /* api callbacks */
566         ot->exec= view_zoom_in_exec;
567         ot->poll= space_image_main_area_poll;
568 }
569
570 static int view_zoom_out_exec(bContext *C, wmOperator *op)
571 {
572         SpaceImage *sima= CTX_wm_space_image(C);
573         ARegion *ar= CTX_wm_region(C);
574
575         sima_zoom_set_factor(sima, ar, 0.8f);
576
577         ED_region_tag_redraw(CTX_wm_region(C));
578         
579         return OPERATOR_FINISHED;
580 }
581
582 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
583 {
584         /* identifiers */
585         ot->name= "View Zoom Out";
586         ot->idname= "IMAGE_OT_view_zoom_out";
587         
588         /* api callbacks */
589         ot->exec= view_zoom_out_exec;
590         ot->poll= space_image_main_area_poll;
591 }
592
593 /********************** view zoom ratio operator *********************/
594
595 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
596 {
597         SpaceImage *sima= CTX_wm_space_image(C);
598         ARegion *ar= CTX_wm_region(C);
599
600         sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"));
601         
602         /* ensure pixel exact locations for draw */
603         sima->xof= (int)sima->xof;
604         sima->yof= (int)sima->yof;
605
606         /* XXX notifier? */
607 #if 0
608         if(image_preview_active(curarea, NULL, NULL)) {
609                 /* recalculates new preview rect */
610                 scrarea_do_windraw(curarea);
611                 image_preview_event(2);
612         }
613 #endif
614
615         ED_region_tag_redraw(CTX_wm_region(C));
616         
617         return OPERATOR_FINISHED;
618 }
619
620 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
621 {
622         /* identifiers */
623         ot->name= "View Zoom Ratio";
624         ot->idname= "IMAGE_OT_view_zoom_ratio";
625         
626         /* api callbacks */
627         ot->exec= view_zoom_ratio_exec;
628         ot->poll= space_image_main_area_poll;
629         
630         /* properties */
631         RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX,
632                 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out.", -FLT_MAX, FLT_MAX);
633 }
634
635 /**************** load/replace/save callbacks ******************/
636
637 /* XXX make dynamic */
638 static const EnumPropertyItem image_file_type_items[] = {
639                 {R_TARGA, "TARGA", 0, "Targa", ""},
640                 {R_RAWTGA, "TARGA RAW", 0, "Targa Raw", ""},
641                 {R_PNG, "PNG", 0, "PNG", ""},
642                 {R_BMP, "BMP", 0, "BMP", ""},
643                 {R_JPEG90, "JPEG", 0, "Jpeg", ""},
644 #ifdef WITH_OPENJPEG
645                 {R_JP2, "JPEG_2000", 0, "Jpeg 2000", ""},
646 #endif
647                 {R_IRIS, "IRIS", 0, "Iris", ""},
648 #ifdef WITH_TIFF
649                 {R_TIFF, "TIFF", 0, "Tiff", ""},
650 #endif
651 #ifdef WITH_DDS
652                 {R_RADHDR, "RADIANCE_HDR", 0, "Radiance HDR", ""},
653 #endif
654 #ifdef WITH_CINEON
655                 {R_CINEON, "CINEON", 0, "Cineon", ""},
656                 {R_DPX, "DPX", 0, "DPX", ""},
657 #endif
658 #ifdef WITH_OPENEXR
659                 {R_OPENEXR, "OPENEXR", 0, "OpenEXR", ""},
660         /* saving sequences of multilayer won't work, they copy buffers  */
661         /*if(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER);
662         else*/
663                 {R_MULTILAYER, "MULTILAYER", 0, "MultiLayer", ""},
664 #endif  
665                 {0, NULL, 0, NULL, NULL}};
666
667 static void image_filesel(bContext *C, wmOperator *op, const char *path)
668 {
669         RNA_string_set(op->ptr, "filepath", path);
670         WM_event_add_fileselect(C, op); 
671 }
672
673 /******************** open image operator ********************/
674
675 static void open_init(bContext *C, wmOperator *op)
676 {
677         PropertyPointerRNA *pprop;
678
679         op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
680         uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
681 }
682
683 static int open_cancel(bContext *C, wmOperator *op)
684 {
685         MEM_freeN(op->customdata);
686         op->customdata= NULL;
687         return OPERATOR_CANCELLED;
688 }
689
690 static int open_exec(bContext *C, wmOperator *op)
691 {
692         SpaceImage *sima= CTX_wm_space_image(C);
693         Scene *scene= CTX_data_scene(C);
694         Object *obedit= CTX_data_edit_object(C);
695         PropertyPointerRNA *pprop;
696         PointerRNA idptr;
697         Image *ima= NULL;
698         char str[FILE_MAX];
699
700         RNA_string_get(op->ptr, "filepath", str);
701         /* default to frame 1 if there's no scene in context */
702
703         errno= 0;
704
705         ima= BKE_add_image_file(str, scene ? scene->r.cfra : 1);
706
707         if(!ima) {
708                 if(op->customdata) MEM_freeN(op->customdata);
709                 BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s.", str, errno ? strerror(errno) : "Unsupported image format");
710                 return OPERATOR_CANCELLED;
711         }
712         
713         if(!op->customdata)
714                 open_init(C, op);
715
716         /* hook into UI */
717         pprop= op->customdata;
718
719         if(pprop->prop) {
720                 /* when creating new ID blocks, use is already 1, but RNA
721                  * pointer se also increases user, so this compensates it */
722                 ima->id.us--;
723
724                 RNA_id_pointer_create(&ima->id, &idptr);
725                 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
726                 RNA_property_update(C, &pprop->ptr, pprop->prop);
727         }
728         else if(sima)
729                 ED_space_image_set(C, sima, scene, obedit, ima);
730
731         // XXX other users?
732         BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD);
733         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
734         
735         MEM_freeN(op->customdata);
736
737         return OPERATOR_FINISHED;
738 }
739
740 static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
741 {
742         SpaceImage *sima= CTX_wm_space_image(C);
743         char *path= (sima && sima->image)? sima->image->name: U.textudir;
744
745         if(!RNA_property_is_set(op->ptr, "relative_path"))
746                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
747
748         if(RNA_property_is_set(op->ptr, "filepath"))
749                 return open_exec(C, op);
750         
751         open_init(C, op);
752
753         image_filesel(C, op, path);
754
755         return OPERATOR_RUNNING_MODAL;
756 }
757
758 void IMAGE_OT_open(wmOperatorType *ot)
759 {
760         /* identifiers */
761         ot->name= "Open";
762         ot->idname= "IMAGE_OT_open";
763         
764         /* api callbacks */
765         ot->exec= open_exec;
766         ot->invoke= open_invoke;
767         ot->cancel= open_cancel;
768
769         /* flags */
770         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
771
772         /* properties */
773         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
774 }
775
776 /******************** replace image operator ********************/
777
778 static int replace_exec(bContext *C, wmOperator *op)
779 {
780         SpaceImage *sima= CTX_wm_space_image(C);
781         char str[FILE_MAX];
782
783         if(!sima->image)
784                 return OPERATOR_CANCELLED;
785         
786         RNA_string_get(op->ptr, "filepath", str);
787         BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
788
789         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
790         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
791
792         return OPERATOR_FINISHED;
793 }
794
795 static int replace_invoke(bContext *C, wmOperator *op, wmEvent *event)
796 {
797         SpaceImage *sima= CTX_wm_space_image(C);
798
799         if(!sima->image)
800                 return OPERATOR_CANCELLED;
801
802         if(RNA_property_is_set(op->ptr, "filepath"))
803                 return replace_exec(C, op);
804
805         if(!RNA_property_is_set(op->ptr, "relative_path"))
806                 RNA_boolean_set(op->ptr, "relative_path", (strncmp(sima->image->name, "//", 2))==0);
807
808         image_filesel(C, op, sima->image->name);
809
810         return OPERATOR_RUNNING_MODAL;
811 }
812
813 void IMAGE_OT_replace(wmOperatorType *ot)
814 {
815         /* identifiers */
816         ot->name= "Replace";
817         ot->idname= "IMAGE_OT_replace";
818         
819         /* api callbacks */
820         ot->exec= replace_exec;
821         ot->invoke= replace_invoke;
822         ot->poll= space_image_poll;
823
824         /* flags */
825         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
826
827         /* properties */
828         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
829 }
830
831 /******************** save image as operator ********************/
832
833 /* assumes name is FILE_MAX */
834 /* ima->name and ibuf->name should end up the same */
835 static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOperator *op, char *path)
836 {
837         Image *ima= ED_space_image(sima);
838         void *lock;
839         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
840
841         if (ibuf) {
842                 int relative= RNA_boolean_get(op->ptr, "relative_path");
843                 int save_copy= (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
844
845                 BLI_path_abs(path, G.sce);
846                 
847                 if(scene->r.scemode & R_EXTENSION)  {
848                         BKE_add_image_extension(path, sima->imtypenr);
849                 }
850                 
851                 /* enforce user setting for RGB or RGBA, but skip BW */
852                 if(scene->r.planes==32)
853                         ibuf->depth= 32;
854                 else if(scene->r.planes==24)
855                         ibuf->depth= 24;
856                 
857                 WM_cursor_wait(1);
858
859                 if(sima->imtypenr==R_MULTILAYER) {
860                         RenderResult *rr= BKE_image_acquire_renderresult(scene, ima);
861                         if(rr) {
862                                 RE_WriteRenderResult(rr, path, scene->r.quality);
863
864                                 if(relative)
865                                         BLI_path_rel(path, G.sce); /* only after saving */
866
867                                 if(!save_copy) {
868                                         BLI_strncpy(ima->name, path, sizeof(ima->name));
869                                         BLI_strncpy(ibuf->name, path, sizeof(ibuf->name));
870
871                                         /* should be function? nevertheless, saving only happens here */
872                                         for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
873                                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
874                                 }
875                         }
876                         else
877                                 BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
878                         BKE_image_release_renderresult(scene, ima);
879                 }
880                 else if (BKE_write_ibuf(scene, ibuf, path, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
881
882                         if(relative)
883                                 BLI_path_rel(path, G.sce); /* only after saving */
884
885                         if(!save_copy) {
886
887                                 BLI_strncpy(ima->name, path, sizeof(ima->name));
888                                 BLI_strncpy(ibuf->name, path, sizeof(ibuf->name));
889
890                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
891
892                                 /* change type? */
893                                 if(ima->type==IMA_TYPE_R_RESULT) {
894                                         ima->type= IMA_TYPE_IMAGE;
895
896                                         /* workaround to ensure the render result buffer is no longer used
897                                          * by this image, otherwise can crash when a new render result is
898                                          * created. */
899                                         if(ibuf->rect && !(ibuf->mall & IB_rect))
900                                                 imb_freerectImBuf(ibuf);
901                                         if(ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
902                                                 imb_freerectfloatImBuf(ibuf);
903                                         if(ibuf->zbuf && !(ibuf->mall & IB_zbuf))
904                                                 IMB_freezbufImBuf(ibuf);
905                                         if(ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
906                                                 IMB_freezbuffloatImBuf(ibuf);
907                                 }
908                                 if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
909                                         ima->source= IMA_SRC_FILE;
910                                         ima->type= IMA_TYPE_IMAGE;
911                                 }
912
913                                 /* name image as how we saved it */
914                                 rename_id(&ima->id, BLI_path_basename(path));
915                         }
916                 } 
917                 else
918                         BKE_reportf(op->reports, RPT_ERROR, "Couldn't write image: %s", path);
919
920                 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
921
922                 WM_cursor_wait(0);
923         }
924
925         ED_space_image_release_buffer(sima, lock);
926 }
927
928 static int save_as_exec(bContext *C, wmOperator *op)
929 {
930         SpaceImage *sima= CTX_wm_space_image(C);
931         Scene *scene= CTX_data_scene(C);
932         Image *ima = ED_space_image(sima);
933         char str[FILE_MAX];
934
935         if(!ima)
936                 return OPERATOR_CANCELLED;
937
938         sima->imtypenr= RNA_enum_get(op->ptr, "file_type");
939         RNA_string_get(op->ptr, "filepath", str);
940
941         save_image_doit(C, sima, scene, op, str);
942
943         return OPERATOR_FINISHED;
944 }
945
946 static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
947 {
948         SpaceImage *sima= CTX_wm_space_image(C);
949         Image *ima = ED_space_image(sima);
950         Scene *scene= CTX_data_scene(C);
951         ImBuf *ibuf;
952         void *lock;
953
954         if(!RNA_property_is_set(op->ptr, "relative_path"))
955                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
956
957         if(RNA_property_is_set(op->ptr, "filepath"))
958                 return save_as_exec(C, op);
959         
960         if(!ima)
961                 return OPERATOR_CANCELLED;
962
963         /* always opens fileselect */
964         ibuf= ED_space_image_acquire_buffer(sima, &lock);
965
966         if(ibuf) {
967                 /* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
968                 if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
969                         sima->imtypenr= R_MULTILAYER;
970                 else if(ima->type==IMA_TYPE_R_RESULT)
971                         sima->imtypenr= scene->r.imtype;
972                 else if (ima->source == IMA_SRC_GENERATED)
973                         sima->imtypenr= R_PNG;
974                 else
975                         sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
976
977                 RNA_enum_set(op->ptr, "file_type", sima->imtypenr);
978                 
979                 if(ibuf->name[0]==0)
980                         BLI_strncpy(ibuf->name, G.ima, FILE_MAX);
981
982                 /* enable save_copy by default for render results */
983                 if(ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) && !RNA_property_is_set(op->ptr, "copy")) {
984                         RNA_boolean_set(op->ptr, "copy", TRUE);
985                 }
986
987                 // XXX note: we can give default menu enums to operator for this 
988                 image_filesel(C, op, ibuf->name);
989
990                 ED_space_image_release_buffer(sima, lock);
991                 
992                 return OPERATOR_RUNNING_MODAL;
993         }
994
995         ED_space_image_release_buffer(sima, lock);
996
997         return OPERATOR_CANCELLED;
998 }
999
1000 void IMAGE_OT_save_as(wmOperatorType *ot)
1001 {
1002         /* identifiers */
1003         ot->name= "Save As";
1004         ot->idname= "IMAGE_OT_save_as";
1005         
1006         /* api callbacks */
1007         ot->exec= save_as_exec;
1008         ot->invoke= save_as_invoke;
1009         ot->poll= space_image_buffer_exists_poll;
1010
1011         /* flags */
1012         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1013
1014         /* properties */
1015         RNA_def_enum(ot->srna, "file_type", image_file_type_items, R_PNG, "File Type", "File type to save image as.");
1016         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
1017
1018         RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
1019 }
1020
1021 /******************** save image operator ********************/
1022
1023 static int save_exec(bContext *C, wmOperator *op)
1024 {
1025         SpaceImage *sima= CTX_wm_space_image(C);
1026         Image *ima = ED_space_image(sima);
1027         void *lock;
1028         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
1029         Scene *scene= CTX_data_scene(C);
1030         RenderResult *rr;
1031         char name[FILE_MAX];
1032
1033         if(!ima || !ibuf) {
1034                 ED_space_image_release_buffer(sima, lock);
1035                 return OPERATOR_CANCELLED;
1036         }
1037
1038         /* if exists, saves over without fileselect */
1039         
1040         BLI_strncpy(name, ibuf->name, FILE_MAX);
1041         if(name[0]==0)
1042                 BLI_strncpy(name, G.ima, FILE_MAX);
1043         else
1044                 BLI_path_abs(name, G.sce);
1045         
1046         if(BLI_exists(name) && BLI_is_writable(name)) {
1047                 rr= BKE_image_acquire_renderresult(scene, ima);
1048
1049                 if(rr)
1050                         sima->imtypenr= R_MULTILAYER;
1051                 else 
1052                         sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
1053
1054                 BKE_image_release_renderresult(scene, ima);
1055                 ED_space_image_release_buffer(sima, lock);
1056                 
1057                 save_image_doit(C, sima, scene, op, name);
1058         }
1059         else {
1060                 ED_space_image_release_buffer(sima, lock);
1061
1062                 BKE_report(op->reports, RPT_ERROR, "Can not save image.");
1063                 return OPERATOR_CANCELLED;
1064         }
1065
1066         return OPERATOR_FINISHED;
1067 }
1068
1069 void IMAGE_OT_save(wmOperatorType *ot)
1070 {
1071         /* identifiers */
1072         ot->name= "Save";
1073         ot->idname= "IMAGE_OT_save";
1074         
1075         /* api callbacks */
1076         ot->exec= save_exec;
1077         ot->poll= space_image_file_exists_poll;
1078
1079         /* flags */
1080         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1081 }
1082
1083 /******************* save sequence operator ********************/
1084
1085 static int save_sequence_exec(bContext *C, wmOperator *op)
1086 {
1087         SpaceImage *sima= CTX_wm_space_image(C);
1088         ImBuf *ibuf;
1089         int tot= 0;
1090         char di[FILE_MAX], fi[FILE_MAX];
1091         
1092         if(sima->image==NULL)
1093                 return OPERATOR_CANCELLED;
1094
1095         if(sima->image->source!=IMA_SRC_SEQUENCE) {
1096                 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences.");
1097                 return OPERATOR_CANCELLED;
1098         }
1099
1100         if(sima->image->type==IMA_TYPE_MULTILAYER) {
1101                 BKE_report(op->reports, RPT_ERROR, "Can't save multilayer sequences.");
1102                 return OPERATOR_CANCELLED;
1103         }
1104         
1105         /* get total */
1106         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
1107                 if(ibuf->userflags & IB_BITMAPDIRTY)
1108                         tot++;
1109         
1110         if(tot==0) {
1111                 BKE_report(op->reports, RPT_WARNING, "No images have been changed.");
1112                 return OPERATOR_CANCELLED;
1113         }
1114
1115         /* get a filename for menu */
1116         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
1117                 if(ibuf->userflags & IB_BITMAPDIRTY)
1118                         break;
1119         
1120         BLI_strncpy(di, ibuf->name, FILE_MAX);
1121         BLI_splitdirstring(di, fi);
1122         
1123         BKE_reportf(op->reports, RPT_INFO, "%d Image(s) will be saved in %s", tot, di);
1124
1125         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) {
1126                 if(ibuf->userflags & IB_BITMAPDIRTY) {
1127                         char name[FILE_MAX];
1128                         BLI_strncpy(name, ibuf->name, sizeof(name));
1129                         
1130                         BLI_path_abs(name, G.sce);
1131
1132                         if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
1133                                 BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s.", name);
1134                                 break;
1135                         }
1136
1137                         BKE_reportf(op->reports, RPT_INFO, "Saved: %s\n", ibuf->name);
1138                         ibuf->userflags &= ~IB_BITMAPDIRTY;
1139                 }
1140         }
1141
1142         return OPERATOR_FINISHED;
1143 }
1144
1145 void IMAGE_OT_save_sequence(wmOperatorType *ot)
1146 {
1147         /* identifiers */
1148         ot->name= "Save Sequence";
1149         ot->idname= "IMAGE_OT_save_sequence";
1150         
1151         /* api callbacks */
1152         ot->exec= save_sequence_exec;
1153         ot->poll= space_image_buffer_exists_poll;
1154
1155         /* flags */
1156         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1157 }
1158
1159 /******************** reload image operator ********************/
1160
1161 static int reload_exec(bContext *C, wmOperator *op)
1162 {
1163         Image *ima= CTX_data_edit_image(C);
1164         SpaceImage *sima= CTX_wm_space_image(C);
1165
1166         if(!ima)
1167                 return OPERATOR_CANCELLED;
1168
1169         // XXX other users?
1170         BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD);
1171
1172         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
1173         
1174         return OPERATOR_FINISHED;
1175 }
1176
1177 void IMAGE_OT_reload(wmOperatorType *ot)
1178 {
1179         /* identifiers */
1180         ot->name= "Reload";
1181         ot->idname= "IMAGE_OT_reload";
1182         
1183         /* api callbacks */
1184         ot->exec= reload_exec;
1185
1186         /* flags */
1187         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1188 }
1189
1190 /********************** new image operator *********************/
1191
1192 static int new_exec(bContext *C, wmOperator *op)
1193 {
1194         SpaceImage *sima;
1195         Scene *scene;
1196         Object *obedit;
1197         Image *ima;
1198         PointerRNA ptr, idptr;
1199         PropertyRNA *prop;
1200         char name[22];
1201         float color[4];
1202         int width, height, floatbuf, uvtestgrid, alpha;
1203
1204         /* retrieve state */
1205         sima= CTX_wm_space_image(C);
1206         scene= (Scene*)CTX_data_scene(C);
1207         obedit= CTX_data_edit_object(C);
1208
1209         RNA_string_get(op->ptr, "name", name);
1210         width= RNA_int_get(op->ptr, "width");
1211         height= RNA_int_get(op->ptr, "height");
1212         floatbuf= RNA_boolean_get(op->ptr, "float");
1213         uvtestgrid= RNA_boolean_get(op->ptr, "uv_test_grid");
1214         RNA_float_get_array(op->ptr, "color", color);
1215         alpha= RNA_boolean_get(op->ptr, "alpha");
1216         
1217         if (!floatbuf && scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
1218                 linearrgb_to_srgb_v3_v3(color, color);
1219
1220         if(!alpha)
1221                 color[3]= 1.0f;
1222
1223         ima = BKE_add_image_size(width, height, name, alpha ? 32 : 24, floatbuf, uvtestgrid, color);
1224
1225         if(!ima)
1226                 return OPERATOR_CANCELLED;
1227
1228         /* hook into UI */
1229         uiIDContextProperty(C, &ptr, &prop);
1230
1231         if(prop) {
1232                 /* when creating new ID blocks, use is already 1, but RNA
1233                  * pointer se also increases user, so this compensates it */
1234                 ima->id.us--;
1235
1236                 RNA_id_pointer_create(&ima->id, &idptr);
1237                 RNA_property_pointer_set(&ptr, prop, idptr);
1238                 RNA_property_update(C, &ptr, prop);
1239         }
1240         else if(sima)
1241                 ED_space_image_set(C, sima, scene, obedit, ima);
1242
1243         // XXX other users?
1244         BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_USER_NEW_IMAGE);
1245         
1246         return OPERATOR_FINISHED;
1247 }
1248
1249 void IMAGE_OT_new(wmOperatorType *ot)
1250 {
1251         PropertyRNA *prop;
1252         static float default_color[4]= {0.0f, 0.0f, 0.0f, 1.0f};
1253         
1254         /* identifiers */
1255         ot->name= "New";
1256         ot->idname= "IMAGE_OT_new";
1257         
1258         /* api callbacks */
1259         ot->exec= new_exec;
1260         ot->invoke= WM_operator_props_popup;
1261
1262         /* flags */
1263         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1264
1265         /* properties */
1266         RNA_def_string(ot->srna, "name", "Untitled", 21, "Name", "Image datablock name.");
1267         RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width.", 1, 16384);
1268         RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height.", 1, 16384);
1269         prop= RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color.", 0.0f, 1.0f);
1270         RNA_def_property_float_array_default(prop, default_color);
1271         RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel.");
1272         RNA_def_boolean(ot->srna, "uv_test_grid", 0, "UV Test Grid", "Fill the image with a grid for UV map testing.");
1273         RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth.");
1274 }
1275
1276 /********************* pack operator *********************/
1277
1278 static int pack_test(bContext *C, wmOperator *op)
1279 {
1280         Image *ima= CTX_data_edit_image(C);
1281         int as_png= RNA_boolean_get(op->ptr, "as_png");
1282
1283         if(!ima)
1284                 return 0;
1285         if(!as_png && ima->packedfile)
1286                 return 0;
1287
1288         if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1289                 BKE_report(op->reports, RPT_ERROR, "Can't pack movie or image sequence.");
1290                 return 0;
1291         }
1292
1293         return 1;
1294 }
1295
1296 static int pack_exec(bContext *C, wmOperator *op)
1297 {
1298         Image *ima= CTX_data_edit_image(C);
1299         ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
1300         int as_png= RNA_boolean_get(op->ptr, "as_png");
1301
1302         if(!pack_test(C, op))
1303                 return OPERATOR_CANCELLED;
1304         
1305         if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
1306                 BKE_report(op->reports, RPT_ERROR, "Can't pack edited image from disk, only as internal PNG.");
1307                 return OPERATOR_CANCELLED;
1308         }
1309
1310         if(as_png)
1311                 BKE_image_memorypack(ima);
1312         else
1313                 ima->packedfile= newPackedFile(op->reports, ima->name);
1314
1315         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
1316         
1317         return OPERATOR_FINISHED;
1318 }
1319
1320 static int pack_invoke(bContext *C, wmOperator *op, wmEvent *event)
1321 {
1322         Image *ima= CTX_data_edit_image(C);
1323         ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
1324         uiPopupMenu *pup;
1325         uiLayout *layout;
1326         int as_png= RNA_boolean_get(op->ptr, "as_png");
1327
1328         if(!pack_test(C, op))
1329                 return OPERATOR_CANCELLED;
1330         
1331         if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
1332                 pup= uiPupMenuBegin(C, "OK", ICON_QUESTION);
1333                 layout= uiPupMenuLayout(pup);
1334                 uiItemBooleanO(layout, "Can't pack edited image from disk. Pack as internal PNG?", 0, op->idname, "as_png", 1);
1335                 uiPupMenuEnd(C, pup);
1336
1337                 return OPERATOR_CANCELLED;
1338         }
1339
1340         return pack_exec(C, op);
1341 }
1342
1343 void IMAGE_OT_pack(wmOperatorType *ot)
1344 {
1345         /* identifiers */
1346         ot->name= "Pack";
1347         ot->description= "Pack an image as embedded data into the .blend file"; 
1348         ot->idname= "IMAGE_OT_pack";
1349         
1350         /* api callbacks */
1351         ot->exec= pack_exec;
1352         ot->invoke= pack_invoke;
1353
1354         /* flags */
1355         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1356
1357         /* properties */
1358         RNA_def_boolean(ot->srna, "as_png", 0, "Pack As PNG", "Pack image as lossless PNG.");
1359 }
1360
1361 /********************* unpack operator *********************/
1362
1363 void unpack_menu(bContext *C, char *opname, Image *ima, char *folder, PackedFile *pf)
1364 {
1365         PointerRNA props_ptr;
1366         uiPopupMenu *pup;
1367         uiLayout *layout;
1368         char line[FILE_MAXDIR + FILE_MAXFILE + 100];
1369         char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
1370         char *abs_name = ima->name;
1371         
1372         strcpy(local_name, abs_name);
1373         BLI_splitdirstring(local_name, fi);
1374         sprintf(local_name, "//%s/%s", folder, fi);
1375
1376         pup= uiPupMenuBegin(C, "Unpack file", 0);
1377         layout= uiPupMenuLayout(pup);
1378
1379         uiItemEnumO(layout, opname, "Remove Pack", 0, "method", PF_REMOVE);
1380
1381         if(strcmp(abs_name, local_name)) {
1382                 switch(checkPackedFile(local_name, pf)) {
1383                         case PF_NOFILE:
1384                                 sprintf(line, "Create %s", local_name);
1385                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1386                                 RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
1387                                 RNA_string_set(&props_ptr, "image", ima->id.name+2);
1388         
1389                                 break;
1390                         case PF_EQUAL:
1391                                 sprintf(line, "Use %s (identical)", local_name);
1392                                 //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
1393                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1394                                 RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
1395                                 RNA_string_set(&props_ptr, "image", ima->id.name+2);
1396                                 
1397                                 break;
1398                         case PF_DIFFERS:
1399                                 sprintf(line, "Use %s (differs)", local_name);
1400                                 //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
1401                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1402                                 RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
1403                                 RNA_string_set(&props_ptr, "image", ima->id.name);
1404                                 
1405                                 sprintf(line, "Overwrite %s", local_name);
1406                                 //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_LOCAL);
1407                                 props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1408                                 RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
1409                                 RNA_string_set(&props_ptr, "image", ima->id.name+2);
1410                                 
1411                                 
1412                                 break;
1413                 }
1414         }
1415         
1416         switch(checkPackedFile(abs_name, pf)) {
1417                 case PF_NOFILE:
1418                         sprintf(line, "Create %s", abs_name);
1419                         //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
1420                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1421                         RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
1422                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1423                         break;
1424                 case PF_EQUAL:
1425                         sprintf(line, "Use %s (identical)", abs_name);
1426                         //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
1427                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1428                         RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
1429                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1430                         break;
1431                 case PF_DIFFERS:
1432                         sprintf(line, "Use %s (differs)", local_name);
1433                         //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
1434                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1435                         RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
1436                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1437                         
1438                         sprintf(line, "Overwrite %s", local_name);
1439                         //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
1440                         props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
1441                         RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
1442                         RNA_string_set(&props_ptr, "image", ima->id.name+2);
1443                         break;
1444         }
1445
1446         uiPupMenuEnd(C, pup);
1447 }
1448
1449 static int unpack_exec(bContext *C, wmOperator *op)
1450 {
1451         Image *ima= CTX_data_edit_image(C);
1452         int method= RNA_enum_get(op->ptr, "method");
1453
1454         /* find the suppplied image by name */
1455         if (RNA_property_is_set(op->ptr, "image")) {
1456                 char imaname[22];
1457                 RNA_string_get(op->ptr, "image", imaname);
1458                 ima = BLI_findstring(&CTX_data_main(C)->image, imaname, offsetof(ID, name) + 2);
1459                 if (!ima) ima = CTX_data_edit_image(C);
1460         }
1461         
1462         if(!ima || !ima->packedfile)
1463                 return OPERATOR_CANCELLED;
1464
1465         if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1466                 BKE_report(op->reports, RPT_ERROR, "Can't unpack movie or image sequence.");
1467                 return OPERATOR_CANCELLED;
1468         }
1469
1470         if(G.fileflags & G_AUTOPACK)
1471                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
1472                 
1473         unpackImage(op->reports, ima, method);
1474         
1475         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
1476
1477         return OPERATOR_FINISHED;
1478 }
1479
1480 static int unpack_invoke(bContext *C, wmOperator *op, wmEvent *event)
1481 {
1482         Image *ima= CTX_data_edit_image(C);
1483
1484         if(RNA_property_is_set(op->ptr, "image"))
1485                 return unpack_exec(C, op);
1486                 
1487         if(!ima || !ima->packedfile)
1488                 return OPERATOR_CANCELLED;
1489
1490         if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1491                 BKE_report(op->reports, RPT_ERROR, "Can't unpack movie or image sequence.");
1492                 return OPERATOR_CANCELLED;
1493         }
1494
1495         if(G.fileflags & G_AUTOPACK)
1496                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
1497         
1498         unpack_menu(C, "IMAGE_OT_unpack", ima, "textures", ima->packedfile);
1499
1500         return OPERATOR_FINISHED;
1501 }
1502
1503 void IMAGE_OT_unpack(wmOperatorType *ot)
1504 {
1505         /* identifiers */
1506         ot->name= "Unpack";
1507         ot->description= "Save an image packed in the .blend file to disk"; 
1508         ot->idname= "IMAGE_OT_unpack";
1509         
1510         /* api callbacks */
1511         ot->exec= unpack_exec;
1512         ot->invoke= unpack_invoke;
1513
1514         /* flags */
1515         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1516
1517         /* properties */
1518         RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack.");
1519         RNA_def_string(ot->srna, "image", "", 21, "Image Name", "Image datablock name to unpack.");
1520 }
1521
1522 /******************** sample image operator ********************/
1523
1524 typedef struct ImageSampleInfo {
1525         ARegionType *art;
1526         void *draw_handle;
1527         int x, y;
1528         int channels;
1529
1530         char col[4];
1531         float colf[4];
1532         int z;
1533         float zf;
1534
1535         char *colp;
1536         float *colfp;
1537         int *zp;
1538         float *zfp;
1539
1540         int draw;
1541 } ImageSampleInfo;
1542
1543 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
1544 {
1545         ImageSampleInfo *info= arg_info;
1546
1547         draw_image_info(ar, info->channels, info->x, info->y, info->colp,
1548                 info->colfp, info->zp, info->zfp);
1549 }
1550
1551 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
1552 {
1553         SpaceImage *sima= CTX_wm_space_image(C);
1554         ARegion *ar= CTX_wm_region(C);
1555         void *lock;
1556         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
1557         ImageSampleInfo *info= op->customdata;
1558         float fx, fy;
1559         int x, y;
1560         
1561         if(ibuf == NULL) {
1562                 ED_space_image_release_buffer(sima, lock);
1563                 return;
1564         }
1565
1566         x= event->x - ar->winrct.xmin;
1567         y= event->y - ar->winrct.ymin;
1568         UI_view2d_region_to_view(&ar->v2d, x, y, &fx, &fy);
1569
1570         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1571                 float *fp;
1572                 char *cp;
1573                 int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y);
1574
1575                 CLAMP(x, 0, ibuf->x-1);
1576                 CLAMP(y, 0, ibuf->y-1);
1577
1578                 info->x= x;
1579                 info->y= y;
1580                 info->draw= 1;
1581                 info->channels= ibuf->channels;
1582
1583                 info->colp= NULL;
1584                 info->colfp= NULL;
1585                 info->zp= NULL;
1586                 info->zfp= NULL;
1587                 
1588                 if(ibuf->rect) {
1589                         cp= (char *)(ibuf->rect + y*ibuf->x + x);
1590
1591                         info->col[0]= cp[0];
1592                         info->col[1]= cp[1];
1593                         info->col[2]= cp[2];
1594                         info->col[3]= cp[3];
1595                         info->colp= info->col;
1596
1597                         info->colf[0]= (float)cp[0]/255.0f;
1598                         info->colf[1]= (float)cp[1]/255.0f;
1599                         info->colf[2]= (float)cp[2]/255.0f;
1600                         info->colf[3]= (float)cp[3]/255.0f;
1601                         info->colfp= info->colf;
1602                 }
1603                 if(ibuf->rect_float) {
1604                         fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1605
1606                         info->colf[0]= fp[0];
1607                         info->colf[1]= fp[1];
1608                         info->colf[2]= fp[2];
1609                         info->colf[3]= fp[3];
1610                         info->colfp= info->colf;
1611                 }
1612
1613                 if(ibuf->zbuf) {
1614                         info->z= ibuf->zbuf[y*ibuf->x + x];
1615                         info->zp= &info->z;
1616                 }
1617                 if(ibuf->zbuf_float) {
1618                         info->zf= ibuf->zbuf_float[y*ibuf->x + x];
1619                         info->zfp= &info->zf;
1620                 }
1621                 
1622                 if(sima->cumap && ibuf->channels==4) {
1623                         /* we reuse this callback for set curves point operators */
1624                         if(RNA_struct_find_property(op->ptr, "point")) {
1625                                 int point= RNA_enum_get(op->ptr, "point");
1626
1627                                 if(point == 1) {
1628                                         curvemapping_set_black_white(sima->cumap, NULL, info->colfp);
1629                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1630                                 }
1631                                 else if(point == 0) {
1632                                         curvemapping_set_black_white(sima->cumap, info->colfp, NULL);
1633                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1634                                 }
1635                         }
1636                 }
1637                                 
1638                 // XXX node curve integration ..
1639 #if 0
1640                 {
1641                         ScrArea *sa, *cur= curarea;
1642                         
1643                         node_curvemap_sample(fp);       /* sends global to node editor */
1644                         for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1645                                 if(sa->spacetype==SPACE_NODE) {
1646                                         areawinset(sa->win);
1647                                         scrarea_do_windraw(sa);
1648                                 }
1649                         }
1650                         node_curvemap_sample(NULL);             /* clears global in node editor */
1651                         curarea= cur;
1652                 }
1653 #endif
1654         }
1655         else
1656                 info->draw= 0;
1657
1658         ED_space_image_release_buffer(sima, lock);
1659         ED_area_tag_redraw(CTX_wm_area(C));
1660 }
1661
1662 static void sample_exit(bContext *C, wmOperator *op)
1663 {
1664         ImageSampleInfo *info= op->customdata;
1665
1666         ED_region_draw_cb_exit(info->art, info->draw_handle);
1667         ED_area_tag_redraw(CTX_wm_area(C));
1668         MEM_freeN(info);
1669 }
1670
1671 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
1672 {
1673         SpaceImage *sima= CTX_wm_space_image(C);
1674         ARegion *ar= CTX_wm_region(C);
1675         ImageSampleInfo *info;
1676
1677         if(!ED_space_image_has_buffer(sima))
1678                 return OPERATOR_CANCELLED;
1679         
1680         info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
1681         info->art= ar->type;
1682         info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
1683         op->customdata= info;
1684
1685         sample_apply(C, op, event);
1686
1687         WM_event_add_modal_handler(C, op);
1688
1689         return OPERATOR_RUNNING_MODAL;
1690 }
1691
1692 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
1693 {
1694         switch(event->type) {
1695                 case LEFTMOUSE:
1696                 case RIGHTMOUSE: // XXX hardcoded
1697                         sample_exit(C, op);
1698                         return OPERATOR_CANCELLED;
1699                 case MOUSEMOVE:
1700                         sample_apply(C, op, event);
1701                         break;
1702         }
1703
1704         return OPERATOR_RUNNING_MODAL;
1705 }
1706
1707 static int sample_cancel(bContext *C, wmOperator *op)
1708 {
1709         sample_exit(C, op);
1710         return OPERATOR_CANCELLED;
1711 }
1712
1713 void IMAGE_OT_sample(wmOperatorType *ot)
1714 {
1715         /* identifiers */
1716         ot->name= "Sample";
1717         ot->idname= "IMAGE_OT_sample";
1718         
1719         /* api callbacks */
1720         ot->invoke= sample_invoke;
1721         ot->modal= sample_modal;
1722         ot->cancel= sample_cancel;
1723         ot->poll= space_image_main_area_poll;
1724
1725         /* flags */
1726         ot->flag= OPTYPE_BLOCKING;
1727 }
1728
1729 /******************** sample line operator ********************/
1730 static int sample_line_exec(bContext *C, wmOperator *op)
1731 {
1732         SpaceImage *sima= CTX_wm_space_image(C);
1733         ARegion *ar= CTX_wm_region(C);
1734         Scene *scene= CTX_data_scene(C);
1735         
1736         int x_start= RNA_int_get(op->ptr, "xstart");
1737         int y_start= RNA_int_get(op->ptr, "ystart");
1738         int x_end= RNA_int_get(op->ptr, "xend");
1739         int y_end= RNA_int_get(op->ptr, "yend");
1740         
1741         void *lock;
1742         ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
1743         Histogram *hist= &sima->sample_line_hist;
1744         
1745         float x1f, y1f, x2f, y2f;
1746         int x1, y1, x2, y2;
1747         int i, x, y;
1748         float *fp;
1749         float rgb[3];
1750         unsigned char *cp;
1751         
1752         if (ibuf == NULL) {
1753                 ED_space_image_release_buffer(sima, lock);
1754                 return OPERATOR_CANCELLED;
1755         }
1756         /* hmmmm */
1757         if (ibuf->channels < 3) {
1758                 ED_space_image_release_buffer(sima, lock);
1759                 return OPERATOR_CANCELLED;
1760         }
1761         
1762         UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
1763         UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
1764         x1= 0.5f+ x1f*ibuf->x;
1765         x2= 0.5f+ x2f*ibuf->x;
1766         y1= 0.5f+ y1f*ibuf->y;
1767         y2= 0.5f+ y2f*ibuf->y;
1768         
1769         hist->channels = 3;
1770         hist->x_resolution = 256;
1771         hist->xmax = 1.0f;
1772         hist->ymax = 1.0f;
1773         
1774         for (i=0; i<256; i++) {
1775                 x= (int)(0.5f + x1 + (float)i*(x2-x1)/255.0f);
1776                 y= (int)(0.5f + y1 + (float)i*(y2-y1)/255.0f);
1777                 
1778                 if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
1779                         hist->data_luma[i] = hist->data_r[i] = hist->data_g[i]= hist->data_b[i] = 0.0f;
1780                 } else {
1781                         if (ibuf->rect_float) {
1782                                 fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1783
1784                                 if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
1785                                         linearrgb_to_srgb_v3_v3(rgb, fp);
1786                                 else
1787                                         copy_v3_v3(rgb, fp);
1788
1789                                 hist->data_r[i] = rgb[0];
1790                                 hist->data_g[i] = rgb[1];
1791                                 hist->data_b[i] = rgb[2];
1792                                 hist->data_luma[i] = (0.299f*rgb[0] + 0.587f*rgb[1] + 0.114f*rgb[2]);
1793                         }
1794                         else if (ibuf->rect) {
1795                                 cp= (unsigned char *)(ibuf->rect + y*ibuf->x + x);
1796                                 hist->data_r[i] = (float)cp[0]/255.0f;
1797                                 hist->data_g[i] = (float)cp[1]/255.0f;
1798                                 hist->data_b[i] = (float)cp[2]/255.0f;
1799                                 hist->data_luma[i] = (0.299f*cp[0] + 0.587f*cp[1] + 0.114f*cp[2])/255;
1800                         }
1801                 }
1802         }
1803         
1804         ED_space_image_release_buffer(sima, lock);
1805         
1806         ED_area_tag_redraw(CTX_wm_area(C));
1807         
1808         return OPERATOR_FINISHED;
1809 }
1810
1811 static int sample_line_invoke(bContext *C, wmOperator *op, wmEvent *event)
1812 {
1813         SpaceImage *sima= CTX_wm_space_image(C);
1814         
1815         if(!ED_space_image_has_buffer(sima))
1816                 return OPERATOR_CANCELLED;
1817         
1818         return WM_gesture_straightline_invoke(C, op, event);
1819 }
1820
1821 void IMAGE_OT_sample_line(wmOperatorType *ot)
1822 {
1823         /* identifiers */
1824         ot->name= "Sample Line";
1825         ot->idname= "IMAGE_OT_sample_line";
1826         
1827         /* api callbacks */
1828         ot->invoke= sample_line_invoke;
1829         ot->modal= WM_gesture_straightline_modal;
1830         ot->exec= sample_line_exec;
1831         ot->poll= space_image_main_area_poll;
1832         
1833         /* flags */
1834         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1835         
1836         WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
1837 }
1838
1839 /******************** set curve point operator ********************/
1840
1841 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
1842 {
1843         static EnumPropertyItem point_items[]= {
1844                 {0, "BLACK_POINT", 0, "Black Point", ""},
1845                 {1, "WHITE_POINT", 0, "White Point", ""},
1846                 {0, NULL, 0, NULL, NULL}};
1847
1848         /* identifiers */
1849         ot->name= "Set Curves Point";
1850         ot->idname= "IMAGE_OT_curves_point_set";
1851
1852         /* flags */
1853         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1854         
1855         /* api callbacks */
1856         ot->invoke= sample_invoke;
1857         ot->modal= sample_modal;
1858         ot->cancel= sample_cancel;
1859         ot->poll= space_image_main_area_poll;
1860
1861         /* properties */
1862         RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves.");
1863 }
1864
1865 /******************** record composite operator *********************/
1866
1867 typedef struct RecordCompositeData {
1868         wmTimer *timer;
1869         int old_cfra;
1870         int sfra, efra;
1871 } RecordCompositeData;
1872
1873 int record_composite_apply(bContext *C, wmOperator *op)
1874 {
1875         SpaceImage *sima= CTX_wm_space_image(C);
1876         RecordCompositeData *rcd= op->customdata;
1877         Scene *scene= CTX_data_scene(C);
1878         ImBuf *ibuf;
1879         
1880         WM_timecursor(CTX_wm_window(C), scene->r.cfra);
1881
1882         // XXX scene->nodetree->test_break= blender_test_break;
1883         // XXX scene->nodetree->test_break= NULL;
1884         
1885         BKE_image_all_free_anim_ibufs(scene->r.cfra);
1886         ntreeCompositTagAnimated(scene->nodetree);
1887         ntreeCompositExecTree(scene->nodetree, &scene->r, scene->r.cfra != rcd->old_cfra);      /* 1 is no previews */
1888
1889         ED_area_tag_redraw(CTX_wm_area(C));
1890         
1891         ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1892         /* save memory in flipbooks */
1893         if(ibuf)
1894                 imb_freerectfloatImBuf(ibuf);
1895         
1896         scene->r.cfra++;
1897
1898         return (scene->r.cfra <= rcd->efra);
1899 }
1900
1901 static int record_composite_init(bContext *C, wmOperator *op)
1902 {
1903         SpaceImage *sima= CTX_wm_space_image(C);
1904         Scene *scene= CTX_data_scene(C);
1905         RecordCompositeData *rcd;
1906
1907         if(sima->iuser.frames < 2)
1908                 return 0;
1909         if(scene->nodetree == NULL)
1910                 return 0;
1911         
1912         op->customdata= rcd= MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData");
1913
1914         rcd->old_cfra= scene->r.cfra;
1915         rcd->sfra= sima->iuser.sfra;
1916         rcd->efra= sima->iuser.sfra + sima->iuser.frames-1;
1917         scene->r.cfra= rcd->sfra;
1918
1919         return 1;
1920 }
1921
1922 static void record_composite_exit(bContext *C, wmOperator *op)
1923 {
1924         Scene *scene= CTX_data_scene(C);
1925         SpaceImage *sima= CTX_wm_space_image(C);
1926         RecordCompositeData *rcd= op->customdata;
1927
1928         scene->r.cfra= rcd->old_cfra;
1929
1930         WM_cursor_restore(CTX_wm_window(C));
1931
1932         if(rcd->timer)
1933                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer);
1934
1935         WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
1936
1937         // XXX play_anim(0);
1938         // XXX allqueue(REDRAWNODE, 1);
1939
1940         MEM_freeN(rcd);
1941 }
1942
1943 static int record_composite_exec(bContext *C, wmOperator *op)
1944 {
1945         if(!record_composite_init(C, op))
1946                 return OPERATOR_CANCELLED;
1947         
1948         while(record_composite_apply(C, op))
1949                 ;
1950         
1951         record_composite_exit(C, op);
1952         
1953         return OPERATOR_FINISHED;
1954 }
1955
1956 static int record_composite_invoke(bContext *C, wmOperator *op, wmEvent *event)
1957 {
1958         RecordCompositeData *rcd= op->customdata;
1959         
1960         if(!record_composite_init(C, op))
1961                 return OPERATOR_CANCELLED;
1962
1963         rcd= op->customdata;
1964         rcd->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.0f);
1965         WM_event_add_modal_handler(C, op);
1966
1967         if(!record_composite_apply(C, op))
1968                 return OPERATOR_FINISHED;
1969
1970         return OPERATOR_RUNNING_MODAL;
1971 }
1972
1973 static int record_composite_modal(bContext *C, wmOperator *op, wmEvent *event)
1974 {
1975         RecordCompositeData *rcd= op->customdata;
1976
1977         switch(event->type) {
1978                 case TIMER:
1979                         if(rcd->timer == event->customdata) {
1980                                 if(!record_composite_apply(C, op)) {
1981                                         record_composite_exit(C, op);
1982                                         return OPERATOR_FINISHED;
1983                                 }
1984                         }
1985                         break;
1986                 case ESCKEY:
1987                         record_composite_exit(C, op);
1988                         return OPERATOR_FINISHED;
1989         }
1990
1991         return OPERATOR_RUNNING_MODAL;
1992 }
1993
1994 static int record_composite_cancel(bContext *C, wmOperator *op)
1995 {
1996         record_composite_exit(C, op);
1997         return OPERATOR_CANCELLED;
1998 }
1999
2000 void IMAGE_OT_record_composite(wmOperatorType *ot)
2001 {
2002         /* identifiers */
2003         ot->name= "Record Composite";
2004         ot->idname= "IMAGE_OT_record_composite";
2005         
2006         /* api callbacks */
2007         ot->exec= record_composite_exec;
2008         ot->invoke= record_composite_invoke;
2009         ot->modal= record_composite_modal;
2010         ot->cancel= record_composite_cancel;
2011         ot->poll= space_image_buffer_exists_poll;
2012 }
2013
2014 /********************* cycle render slot operator *********************/
2015
2016 static int cycle_render_slot_poll(bContext *C)
2017 {
2018         Image *ima= CTX_data_edit_image(C);
2019
2020         return (ima && ima->type == IMA_TYPE_R_RESULT);
2021 }
2022
2023 static int cycle_render_slot_exec(bContext *C, wmOperator *op)
2024 {
2025         Image *ima= CTX_data_edit_image(C);
2026         int a, slot, cur= ima->render_slot;
2027
2028         for(a=1; a<IMA_MAX_RENDER_SLOT; a++) {
2029                 slot= (cur+a)%IMA_MAX_RENDER_SLOT;
2030
2031                 if(ima->renders[slot] || slot == ima->last_render_slot) {
2032                         ima->render_slot= slot;
2033                         break;
2034                 }
2035         }
2036
2037         if(a == IMA_MAX_RENDER_SLOT)
2038                 ima->render_slot= ((cur == 1)? 0: 1);
2039         
2040         WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
2041
2042         return OPERATOR_FINISHED;
2043 }
2044
2045 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
2046 {
2047         /* identifiers */
2048         ot->name= "Cycle Render Slot";
2049         ot->idname= "IMAGE_OT_cycle_render_slot";
2050         
2051         /* api callbacks */
2052         ot->exec= cycle_render_slot_exec;
2053         ot->poll= cycle_render_slot_poll;
2054
2055         /* flags */
2056         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2057 }
2058
2059 /******************** TODO ********************/
2060
2061 /* XXX notifier? */
2062
2063 /* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
2064
2065 void ED_image_update_frame(const bContext *C)
2066 {
2067         Main *mainp= CTX_data_main(C);
2068         Scene *scene= CTX_data_scene(C);
2069         wmWindowManager *wm= CTX_wm_manager(C);
2070         wmWindow *win;
2071         Tex *tex;
2072         
2073         /* texture users */
2074         for(tex= mainp->tex.first; tex; tex= tex->id.next) {
2075                 if(tex->type==TEX_IMAGE && tex->ima) {
2076                         if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
2077                                 if(tex->iuser.flag & IMA_ANIM_ALWAYS)
2078                                         BKE_image_user_calc_frame(&tex->iuser, scene->r.cfra, 0);
2079                         }
2080                 }
2081         }
2082         
2083         /* image window, compo node users */
2084         if(wm) {
2085                 for(win= wm->windows.first; win; win= win->next) {
2086                         ScrArea *sa;
2087                         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
2088                                 if(sa->spacetype==SPACE_VIEW3D) {
2089                                         View3D *v3d= sa->spacedata.first;
2090                                         BGpic *bgpic;
2091                                         for(bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next)
2092                                                 if(bgpic->iuser.flag & IMA_ANIM_ALWAYS)
2093                                                         BKE_image_user_calc_frame(&bgpic->iuser, scene->r.cfra, 0);
2094                                 }
2095                                 else if(sa->spacetype==SPACE_IMAGE) {
2096                                         SpaceImage *sima= sa->spacedata.first;
2097                                         if(sima->iuser.flag & IMA_ANIM_ALWAYS)
2098                                                 BKE_image_user_calc_frame(&sima->iuser, scene->r.cfra, 0);
2099                                 }
2100                                 else if(sa->spacetype==SPACE_NODE) {
2101                                         SpaceNode *snode= sa->spacedata.first;
2102                                         if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
2103                                                 bNode *node;
2104                                                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
2105                                                         if(node->id && node->type==CMP_NODE_IMAGE) {
2106                                                                 Image *ima= (Image *)node->id;
2107                                                                 ImageUser *iuser= node->storage;
2108                                                                 if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
2109                                                                         if(iuser->flag & IMA_ANIM_ALWAYS)
2110                                                                                 BKE_image_user_calc_frame(iuser, scene->r.cfra, 0);
2111                                                         }
2112                                                 }
2113                                         }
2114                                 }
2115                         }
2116                 }
2117         }
2118 }
2119