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