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