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