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