2.5
[blender-staging.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_screen.h"
51
52 #include "BLI_arithb.h"
53 #include "BLI_blenlib.h"
54
55 #include "IMB_imbuf.h"
56 #include "IMB_imbuf_types.h"
57
58 #include "RE_pipeline.h"
59
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62 #include "RNA_types.h"
63
64 #include "ED_screen.h"
65 #include "ED_uvedit.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "image_intern.h"
71
72 void imagespace_composite_flipbook(SpaceImage *sima, Scene *scene)
73 {
74         ImBuf *ibuf;
75         int cfrao= scene->r.cfra;
76         int sfra, efra;
77         
78         if(sima->iuser.frames<2)
79                 return;
80         if(scene->nodetree==NULL)
81                 return;
82         
83         sfra= sima->iuser.sfra;
84         efra= sima->iuser.sfra + sima->iuser.frames-1;
85         scene->nodetree->test_break= NULL; // XXX blender_test_break;
86         
87         for(scene->r.cfra=sfra; scene->r.cfra<=efra; scene->r.cfra++) {
88                 
89                 // XXX set_timecursor(CFRA);
90                 
91                 BKE_image_all_free_anim_ibufs(CFRA);
92                 ntreeCompositTagAnimated(scene->nodetree);
93                 ntreeCompositExecTree(scene->nodetree, &scene->r, scene->r.cfra!=cfrao);        /* 1 is no previews */
94                 
95                 // XXX force_draw(0);
96                 
97                 ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
98                 /* save memory in flipbooks */
99                 if(ibuf)
100                         imb_freerectfloatImBuf(ibuf);
101                 
102                 // XXX if(blender_test_break())
103                 // XXX  break;
104         }
105         scene->nodetree->test_break= NULL;
106         // XXX waitcursor(0);
107         
108         // XXX play_anim(0);
109         
110         // XXX allqueue(REDRAWNODE, 1);
111         // XXX allqueue(REDRAWIMAGE, 1);
112         
113         scene->r.cfra= cfrao;
114 }
115
116 /******************** view navigation utilities *********************/
117
118 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom)
119 {
120         float oldzoom= sima->zoom;
121         int width, height;
122
123         sima->zoom= zoom;
124
125         if (sima->zoom > 0.1f && sima->zoom < 4.0f)
126                 return;
127
128         /* check zoom limits */
129         get_space_image_size(sima, &width, &height);
130
131         width *= sima->zoom;
132         height *= sima->zoom;
133
134         if((width < 4) && (height < 4))
135                 sima->zoom= oldzoom;
136         else if((ar->winrct.xmax - ar->winrct.xmin) <= sima->zoom)
137                 sima->zoom= oldzoom;
138         else if((ar->winrct.ymax - ar->winrct.ymin) <= sima->zoom)
139                 sima->zoom= oldzoom;
140 }
141
142 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac)
143 {
144         sima_zoom_set(sima, ar, sima->zoom*zoomfac);
145 }
146
147 int space_image_main_area_poll(bContext *C)
148 {
149         SpaceLink *slink= CTX_wm_space_data(C);
150         ARegion *ar= CTX_wm_region(C);
151
152         if(slink && (slink->spacetype == SPACE_IMAGE))
153                 return (ar && ar->type->regionid == RGN_TYPE_WINDOW);
154         
155         return 0;
156 }
157
158 /********************** view pan operator *********************/
159
160 typedef struct ViewPanData {
161         float x, y;
162         float xof, yof;
163 } ViewPanData;
164
165 static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
166 {
167         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
168         ViewPanData *vpd;
169
170         op->customdata= vpd= MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
171         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
172
173         vpd->x= event->x;
174         vpd->y= event->y;
175         vpd->xof= sima->xof;
176         vpd->yof= sima->yof;
177
178         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
179 }
180
181 static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
182 {
183         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
184         ViewPanData *vpd= op->customdata;
185
186         if(cancel) {
187                 sima->xof= vpd->xof;
188                 sima->yof= vpd->yof;
189                 ED_area_tag_redraw(CTX_wm_area(C));
190         }
191
192         WM_cursor_restore(CTX_wm_window(C));
193         MEM_freeN(op->customdata);
194 }
195
196 static int view_pan_exec(bContext *C, wmOperator *op)
197 {
198         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
199         float offset[2];
200
201         RNA_float_get_array(op->ptr, "offset", offset);
202         sima->xof += offset[0];
203         sima->yof += offset[1];
204
205         ED_area_tag_redraw(CTX_wm_area(C));
206
207         /* XXX notifier? */
208 #if 0
209         if(image_preview_active(curarea, NULL, NULL)) {
210                 /* recalculates new preview rect */
211                 scrarea_do_windraw(curarea);
212                 image_preview_event(2);
213         }
214 #endif
215         
216         return OPERATOR_FINISHED;
217 }
218
219 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
220 {
221         view_pan_init(C, op, event);
222         return OPERATOR_RUNNING_MODAL;
223 }
224
225 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
226 {
227         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
228         ViewPanData *vpd= op->customdata;
229         float offset[2];
230
231         switch(event->type) {
232                 case MOUSEMOVE:
233                         sima->xof= vpd->xof;
234                         sima->yof= vpd->yof;
235                         offset[0]= (vpd->x - event->x)/sima->zoom;
236                         offset[1]= (vpd->y - event->y)/sima->zoom;
237                         RNA_float_set_array(op->ptr, "offset", offset);
238                         view_pan_exec(C, op);
239                         break;
240                 case MIDDLEMOUSE:
241                         if(event->val==0) {
242                                 view_pan_exit(C, op, 0);
243                                 return OPERATOR_FINISHED;
244                         }
245                         break;
246         }
247
248         return OPERATOR_RUNNING_MODAL;
249 }
250
251 static int view_pan_cancel(bContext *C, wmOperator *op)
252 {
253         view_pan_exit(C, op, 1);
254         return OPERATOR_CANCELLED;
255 }
256
257 void IMAGE_OT_view_pan(wmOperatorType *ot)
258 {
259         /* identifiers */
260         ot->name= "View Pan";
261         ot->idname= "IMAGE_OT_view_pan";
262         
263         /* api callbacks */
264         ot->exec= view_pan_exec;
265         ot->invoke= view_pan_invoke;
266         ot->modal= view_pan_modal;
267         ot->cancel= view_pan_cancel;
268         ot->poll= space_image_main_area_poll;
269         
270         /* flags */
271         ot->flag= OPTYPE_REGISTER;
272         
273         /* properties */
274         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
275                 "Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
276 }
277
278 /********************** view zoom operator *********************/
279
280 typedef struct ViewZoomData {
281         float x, y;
282         float zoom;
283 } ViewZoomData;
284
285 static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
286 {
287         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
288         ViewZoomData *vpd;
289
290         op->customdata= vpd= MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
291         WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
292
293         vpd->x= event->x;
294         vpd->y= event->y;
295         vpd->zoom= sima->zoom;
296
297         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
298 }
299
300 static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
301 {
302         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
303         ViewZoomData *vpd= op->customdata;
304
305         if(cancel) {
306                 sima->zoom= vpd->zoom;
307                 ED_area_tag_redraw(CTX_wm_area(C));
308         }
309
310         WM_cursor_restore(CTX_wm_window(C));
311         MEM_freeN(op->customdata);
312 }
313
314 static int view_zoom_exec(bContext *C, wmOperator *op)
315 {
316         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
317         ARegion *ar= CTX_wm_region(C);
318
319         sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"));
320
321         ED_area_tag_redraw(CTX_wm_area(C));
322
323         /* XXX notifier? */
324 #if 0
325         if(image_preview_active(curarea, NULL, NULL)) {
326                 /* recalculates new preview rect */
327                 scrarea_do_windraw(curarea);
328                 image_preview_event(2);
329         }
330 #endif
331         
332         return OPERATOR_FINISHED;
333 }
334
335 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
336 {
337         view_zoom_init(C, op, event);
338         return OPERATOR_RUNNING_MODAL;
339 }
340
341 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
342 {
343         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
344         ARegion *ar= CTX_wm_region(C);
345         ViewZoomData *vpd= op->customdata;
346         float factor;
347
348         switch(event->type) {
349                 case MOUSEMOVE:
350                         factor= 1.0 + (vpd->x-event->x+vpd->y-event->y)/300.0f;
351                         RNA_float_set(op->ptr, "factor", factor);
352                         sima_zoom_set(sima, ar, vpd->zoom*factor);
353                         ED_area_tag_redraw(CTX_wm_area(C));
354                         break;
355                 case MIDDLEMOUSE:
356                         if(event->val==0) {
357                                 view_zoom_exit(C, op, 0);
358                                 return OPERATOR_FINISHED;
359                         }
360                         break;
361         }
362
363         return OPERATOR_RUNNING_MODAL;
364 }
365
366 static int view_zoom_cancel(bContext *C, wmOperator *op)
367 {
368         view_zoom_exit(C, op, 1);
369         return OPERATOR_CANCELLED;
370 }
371
372 void IMAGE_OT_view_zoom(wmOperatorType *ot)
373 {
374         /* identifiers */
375         ot->name= "View Zoom";
376         ot->idname= "IMAGE_OT_view_zoom";
377         
378         /* api callbacks */
379         ot->exec= view_zoom_exec;
380         ot->invoke= view_zoom_invoke;
381         ot->modal= view_zoom_modal;
382         ot->cancel= view_zoom_cancel;
383         ot->poll= space_image_main_area_poll;
384         
385         /* flags */
386         ot->flag= OPTYPE_REGISTER;
387         
388         /* properties */
389         RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX,
390                 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.", -FLT_MAX, FLT_MAX);
391 }
392
393 /********************** view all operator *********************/
394
395 /* Updates the fields of the View2D member of the SpaceImage struct.
396  * Default behavior is to reset the position of the image and set the zoom to 1
397  * If the image will not fit within the window rectangle, the zoom is adjusted */
398
399 static int view_all_exec(bContext *C, wmOperator *op)
400 {
401         SpaceImage *sima;
402         ARegion *ar;
403         Scene *scene;
404         Object *obedit;
405         Image *ima;
406         ImBuf *ibuf;
407         float aspx, aspy, zoomx, zoomy, w, h;
408         int width, height;
409
410         /* retrieve state */
411         sima= (SpaceImage*)CTX_wm_space_data(C);
412         ar= CTX_wm_region(C);
413         scene= (Scene*)CTX_data_scene(C);
414         obedit= CTX_data_edit_object(C);
415
416         ima= get_space_image(sima);
417         ibuf= get_space_image_buffer(sima);
418         get_space_image_size(sima, &width, &height);
419         get_space_image_aspect(sima, &aspx, &aspy);
420
421         w= width*aspx;
422         h= height*aspy;
423         
424         /* check if the image will fit in the image with zoom==1 */
425         width = ar->winrct.xmax - ar->winrct.xmin + 1;
426         height = ar->winrct.ymax - ar->winrct.ymin + 1;
427
428         if((w >= width || h >= height) && (width > 0 && height > 0)) {
429                 /* find the zoom value that will fit the image in the image space */
430                 zoomx= width/w;
431                 zoomy= height/h;
432                 sima_zoom_set(sima, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy)));
433         }
434         else
435                 sima_zoom_set(sima, ar, 1.0f);
436
437         sima->xof= sima->yof= 0.0f;
438
439         ED_area_tag_redraw(CTX_wm_area(C));
440         
441         return OPERATOR_FINISHED;
442 }
443
444 void IMAGE_OT_view_all(wmOperatorType *ot)
445 {
446         /* identifiers */
447         ot->name= "View All";
448         ot->idname= "IMAGE_OT_view_all";
449         
450         /* api callbacks */
451         ot->exec= view_all_exec;
452         ot->poll= space_image_main_area_poll;
453         
454         /* flags */
455         ot->flag= OPTYPE_REGISTER;
456 }
457
458 /********************** view selected operator *********************/
459
460 static int view_selected_exec(bContext *C, wmOperator *op)
461 {
462         SpaceImage *sima;
463         ARegion *ar;
464         Scene *scene;
465         Object *obedit;
466         Image *ima;
467         ImBuf *ibuf;
468         float size, min[2], max[2], d[2];
469         int width, height;
470
471         /* retrieve state */
472         sima= (SpaceImage*)CTX_wm_space_data(C);
473         ar= CTX_wm_region(C);
474         scene= (Scene*)CTX_data_scene(C);
475         obedit= CTX_data_edit_object(C);
476
477         ima= get_space_image(sima);
478         ibuf= get_space_image_buffer(sima);
479         get_space_image_size(sima, &width, &height);
480
481         /* get bounds */
482         if(!ED_uvedit_minmax(scene, ima, obedit, min, max))
483                 return OPERATOR_CANCELLED;
484
485         /* adjust offset and zoom */
486         sima->xof= (int)(((min[0] + max[0])*0.5f - 0.5f)*width);
487         sima->yof= (int)(((min[1] + max[1])*0.5f - 0.5f)*height);
488
489         d[0]= max[0] - min[0];
490         d[1]= max[1] - min[1];
491         size= 0.5*MAX2(d[0], d[1])*MAX2(width, height)/256.0f;
492         
493         if(size<=0.01) size= 0.01;
494         sima_zoom_set(sima, ar, 0.7/size);
495
496         ED_area_tag_redraw(CTX_wm_area(C));
497         
498         return OPERATOR_FINISHED;
499 }
500
501 void IMAGE_OT_view_selected(wmOperatorType *ot)
502 {
503         /* identifiers */
504         ot->name= "View Center";
505         ot->idname= "IMAGE_OT_view_selected";
506         
507         /* api callbacks */
508         ot->exec= view_selected_exec;
509         ot->poll= ED_operator_uvedit;
510         
511         /* flags */
512         ot->flag= OPTYPE_REGISTER;
513 }
514
515 /********************** view zoom in/out operator *********************/
516
517 static int view_zoom_in_exec(bContext *C, wmOperator *op)
518 {
519         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
520         ARegion *ar= CTX_wm_region(C);
521
522         sima_zoom_set_factor(sima, ar, 1.25f);
523
524         ED_area_tag_redraw(CTX_wm_area(C));
525         
526         return OPERATOR_FINISHED;
527 }
528
529 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
530 {
531         /* identifiers */
532         ot->name= "View Zoom In";
533         ot->idname= "IMAGE_OT_view_zoom_in";
534         
535         /* api callbacks */
536         ot->exec= view_zoom_in_exec;
537         ot->poll= space_image_main_area_poll;
538         
539         /* flags */
540         ot->flag= OPTYPE_REGISTER;
541 }
542
543 static int view_zoom_out_exec(bContext *C, wmOperator *op)
544 {
545         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
546         ARegion *ar= CTX_wm_region(C);
547
548         sima_zoom_set_factor(sima, ar, 0.8f);
549
550         ED_area_tag_redraw(CTX_wm_area(C));
551         
552         return OPERATOR_FINISHED;
553 }
554
555 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
556 {
557         /* identifiers */
558         ot->name= "View Zoom Out";
559         ot->idname= "IMAGE_OT_view_zoom_out";
560         
561         /* api callbacks */
562         ot->exec= view_zoom_out_exec;
563         ot->poll= space_image_main_area_poll;
564         
565         /* flags */
566         ot->flag= OPTYPE_REGISTER;
567 }
568
569 /********************** view zoom ratio operator *********************/
570
571 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
572 {
573         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
574         ARegion *ar= CTX_wm_region(C);
575
576         sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"));
577         
578         /* ensure pixel exact locations for draw */
579         sima->xof= (int)sima->xof;
580         sima->yof= (int)sima->yof;
581
582         /* XXX notifier? */
583 #if 0
584         if(image_preview_active(curarea, NULL, NULL)) {
585                 /* recalculates new preview rect */
586                 scrarea_do_windraw(curarea);
587                 image_preview_event(2);
588         }
589 #endif
590
591         ED_area_tag_redraw(CTX_wm_area(C));
592         
593         return OPERATOR_FINISHED;
594 }
595
596 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
597 {
598         /* identifiers */
599         ot->name= "View Zoom Ratio";
600         ot->idname= "IMAGE_OT_view_zoom_ratio";
601         
602         /* api callbacks */
603         ot->exec= view_zoom_ratio_exec;
604         ot->poll= space_image_main_area_poll;
605         
606         /* flags */
607         ot->flag= OPTYPE_REGISTER;
608         
609         /* properties */
610         RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX,
611                 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out.", -FLT_MAX, FLT_MAX);
612 }
613
614 /* Image functions */
615
616 #if 0
617 static void load_image_filesel(SpaceImage *sima, Scene *scene, Object *obedit, char *str)       /* called from fileselect */
618 {
619         Image *ima= NULL;
620
621         ima= BKE_add_image_file(str, scene->r.cfra);
622         if(ima) {
623                 BKE_image_signal(ima, &sima->iuser, IMA_SIGNAL_RELOAD);
624                 set_space_image(sima, scene, obedit, ima);
625         }
626         // XXX BIF_undo_push("Load image UV");
627         // XXX allqueue(REDRAWIMAGE, 0);
628 }
629
630 static void replace_image_filesel(SpaceImage *sima, char *str)          /* called from fileselect */
631 {
632         if (!sima->image)
633                 return;
634         
635         BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
636         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
637         // XXX BIF_undo_push("Replace image UV");
638         // XXX allqueue(REDRAWIMAGE, 0);
639         // XXX allqueue(REDRAWVIEW3D, 0);
640 }
641 #endif
642
643 static void save_image_doit(SpaceImage *sima, Scene *scene, char *name)
644 {
645         Image *ima= get_space_image(sima);
646         ImBuf *ibuf= get_space_image_buffer(sima);
647         int len;
648         char str[FILE_MAXDIR+FILE_MAXFILE];
649
650         if (ibuf) {
651                 BLI_strncpy(str, name, sizeof(str));
652
653                 BLI_convertstringcode(str, G.sce);
654                 BLI_convertstringframe(str, scene->r.cfra);
655                 
656                 
657                 if(scene->r.scemode & R_EXTENSION)  {
658                         BKE_add_image_extension(scene, str, sima->imtypenr);
659                         BKE_add_image_extension(scene, name, sima->imtypenr);
660                 }
661                 
662                 if (1) { // XXX saveover(str)) {
663                         
664                         /* enforce user setting for RGB or RGBA, but skip BW */
665                         if(scene->r.planes==32)
666                                 ibuf->depth= 32;
667                         else if(scene->r.planes==24)
668                                 ibuf->depth= 24;
669                         
670                         // XXX waitcursor(1);
671                         if(sima->imtypenr==R_MULTILAYER) {
672                                 RenderResult *rr= BKE_image_get_renderresult(scene, ima);
673                                 if(rr) {
674                                         RE_WriteRenderResult(rr, str, scene->r.quality);
675                                         
676                                         BLI_strncpy(ima->name, name, sizeof(ima->name));
677                                         BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
678                                         
679                                         /* should be function? nevertheless, saving only happens here */
680                                         for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
681                                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
682                                         
683                                 }
684                                 else; // XXX error("Did not write, no Multilayer Image");
685                         }
686                         else if (BKE_write_ibuf(scene, ibuf, str, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
687                                 BLI_strncpy(ima->name, name, sizeof(ima->name));
688                                 BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
689                                 
690                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
691                                 
692                                 /* change type? */
693                                 if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
694                                         ima->source= IMA_SRC_FILE;
695                                         ima->type= IMA_TYPE_IMAGE;
696                                 }
697                                 if(ima->type==IMA_TYPE_R_RESULT)
698                                         ima->type= IMA_TYPE_IMAGE;
699                                 
700                                 /* name image as how we saved it */
701                                 len= strlen(str);
702                                 while (len > 0 && str[len - 1] != '/' && str[len - 1] != '\\') len--;
703                                 rename_id(&ima->id, str+len);
704                         } 
705                         else {
706                                 ; // XXX error("Couldn't write image: %s", str);
707                         }
708
709                         // XXX allqueue(REDRAWHEADERS, 0);
710                         // XXX allqueue(REDRAWBUTSSHADING, 0);
711
712                         // XXX waitcursor(0);
713                 }
714         }
715 }
716
717 void open_image_sima(SpaceImage *sima, short imageselect)
718 {
719         char name[FILE_MAXDIR+FILE_MAXFILE];
720
721         if(sima->image)
722                 BLI_strncpy(name, sima->image->name, sizeof(name));
723         else
724                 BLI_strncpy(name, U.textudir, sizeof(name));
725
726         if(imageselect)
727                 ; // XXX activate_imageselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
728         else
729                 ; // XXX activate_fileselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
730 }
731
732 void replace_image_sima(SpaceImage *sima, short imageselect)
733 {
734         char name[FILE_MAXDIR+FILE_MAXFILE];
735
736         if(sima->image)
737                 BLI_strncpy(name, sima->image->name, sizeof(name));
738         else
739                 BLI_strncpy(name, U.textudir, sizeof(name));
740         
741         if(imageselect)
742                 ; // XXX activate_imageselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
743         else
744                 ; // XXX activate_fileselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
745 }
746
747
748 static char *filesel_imagetype_string(Image *ima)
749 {
750         char *strp, *str= MEM_callocN(14*32, "menu for filesel");
751         
752         strp= str;
753         str += sprintf(str, "Save Image as: %%t|");
754         str += sprintf(str, "Targa %%x%d|", R_TARGA);
755         str += sprintf(str, "Targa Raw %%x%d|", R_RAWTGA);
756         str += sprintf(str, "PNG %%x%d|", R_PNG);
757         str += sprintf(str, "BMP %%x%d|", R_BMP);
758         str += sprintf(str, "Jpeg %%x%d|", R_JPEG90);
759         str += sprintf(str, "Iris %%x%d|", R_IRIS);
760         if(G.have_libtiff)
761                 str += sprintf(str, "Tiff %%x%d|", R_TIFF);
762         str += sprintf(str, "Radiance HDR %%x%d|", R_RADHDR);
763         str += sprintf(str, "Cineon %%x%d|", R_CINEON);
764         str += sprintf(str, "DPX %%x%d|", R_DPX);
765 #ifdef WITH_OPENEXR
766         str += sprintf(str, "OpenEXR %%x%d|", R_OPENEXR);
767         /* saving sequences of multilayer won't work, they copy buffers  */
768         if(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER);
769         else str += sprintf(str, "MultiLayer %%x%d|", R_MULTILAYER);
770 #endif  
771         return strp;
772 }
773
774 /* always opens fileselect */
775 void save_as_image_sima(SpaceImage *sima, Scene *scene)
776 {
777         Image *ima = sima->image;
778         ImBuf *ibuf= get_space_image_buffer(sima);
779         char name[FILE_MAXDIR+FILE_MAXFILE];
780
781         if (ima) {
782                 strcpy(name, ima->name);
783
784                 if (ibuf) {
785                         char *strp;
786                         
787                         strp= filesel_imagetype_string(ima);
788                         
789                         /* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
790                         if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
791                                 sima->imtypenr= R_MULTILAYER;
792                         else if(ima->type==IMA_TYPE_R_RESULT)
793                                 sima->imtypenr= scene->r.imtype;
794                         else sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
795                         
796                         // XXX activate_fileselect_menu(FILE_SPECIAL, "Save Image", name, strp, &sima->imtypenr, save_image_doit);
797                 }
798         }
799 }
800
801 /* if exists, saves over without fileselect */
802 void save_image_sima(SpaceImage *sima, Scene *scene)
803 {
804         Image *ima = get_space_image(sima);
805         ImBuf *ibuf= get_space_image_buffer(sima);
806         char name[FILE_MAXDIR+FILE_MAXFILE];
807
808         if (ima) {
809                 strcpy(name, ima->name);
810
811                 if (ibuf) {
812                         if (BLI_exists(ibuf->name)) {
813                                 if(BKE_image_get_renderresult(scene, ima)) 
814                                         sima->imtypenr= R_MULTILAYER;
815                                 else 
816                                         sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
817                                 
818                                 save_image_doit(sima, scene, ibuf->name);
819                         }
820                         else
821                                 save_as_image_sima(sima, scene);
822                 }
823         }
824 }
825
826 void save_image_sequence_sima(SpaceImage *sima)
827 {
828         ImBuf *ibuf;
829         int tot= 0;
830         char di[FILE_MAX], fi[FILE_MAX];
831         
832         if(sima->image==NULL)
833                 return;
834         if(sima->image->source!=IMA_SRC_SEQUENCE)
835                 return;
836         if(sima->image->type==IMA_TYPE_MULTILAYER) {
837                 // XXX error("Cannot save Multilayer Sequences");
838                 return;
839         }
840         
841         /* get total */
842         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
843                 if(ibuf->userflags & IB_BITMAPDIRTY)
844                         tot++;
845         
846         if(tot==0) {
847                 // XXX notice("No Images have been changed");
848                 return;
849         }
850         /* get a filename for menu */
851         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
852                 if(ibuf->userflags & IB_BITMAPDIRTY)
853                         break;
854         
855         BLI_strncpy(di, ibuf->name, FILE_MAX);
856         BLI_splitdirstring(di, fi);
857         
858         sprintf(fi, "%d Image(s) will be saved in %s", tot, di);
859         if(1) { // XXX okee(fi)) {
860                 
861                 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) {
862                         if(ibuf->userflags & IB_BITMAPDIRTY) {
863                                 char name[FILE_MAX];
864                                 BLI_strncpy(name, ibuf->name, sizeof(name));
865                                 
866                                 BLI_convertstringcode(name, G.sce);
867
868                                 if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
869                                         // XXX error("Could not write image", name);
870                                         break;
871                                 }
872                                 printf("Saved: %s\n", ibuf->name);
873                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
874                         }
875                 }
876         }
877 }
878
879 void reload_image_sima(SpaceImage *sima)
880 {
881         if (sima ) {
882                 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
883                 /* set_space_image(sima, scene, obedit, NULL); - do we really need this? */
884         }
885
886         // XXX allqueue(REDRAWIMAGE, 0);
887         // XXX allqueue(REDRAWVIEW3D, 0);
888         // XXX BIF_preview_changed(ID_TE);
889 }
890
891 void new_image_sima(SpaceImage *sima, Scene *scene, Object *obedit)
892 {
893         static int width= 1024, height= 1024;
894         static short uvtestgrid= 0;
895         static int floatbuf=0;
896         static float color[] = {0, 0, 0, 1};
897         char name[22];
898         Image *ima;
899         
900         strcpy(name, "Untitled");
901
902 #if 0
903         add_numbut(0, TEX, "Name:", 0, 21, name, NULL);
904         add_numbut(1, NUM|INT, "Width:", 1, 16384, &width, NULL);
905         add_numbut(2, NUM|INT, "Height:", 1, 16384, &height, NULL);
906         add_numbut(3, COL, "", 0, 0, &color, NULL);
907         add_numbut(4, NUM|FLO, "Alpha:", 0.0, 1.0, &color[3], NULL);
908         add_numbut(5, TOG|SHO, "UV Test Grid", 0, 0, &uvtestgrid, NULL);
909         add_numbut(6, TOG|INT, "32 bit Float", 0, 0, &floatbuf, NULL);
910         if (!do_clever_numbuts("New Image", 7, REDRAW))
911                 return;
912 #endif
913
914         ima = BKE_add_image_size(width, height, name, floatbuf, uvtestgrid, color);
915         set_space_image(sima, scene, obedit, ima);
916         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE);
917         // XXX BIF_undo_push("Add image");
918
919         // XXX allqueue(REDRAWIMAGE, 0);
920         // XXX allqueue(REDRAWVIEW3D, 0);
921 }
922
923 void pack_image_sima(SpaceImage *sima)
924 {
925         Image *ima = sima->image;
926
927         if (ima) {
928                 if(ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE) {
929                         if (ima->packedfile) {
930                                 if (G.fileflags & G_AUTOPACK)
931                                         if (1) // XXX okee("Disable AutoPack?"))
932                                                 G.fileflags &= ~G_AUTOPACK;
933                                 
934                                 if ((G.fileflags & G_AUTOPACK) == 0) {
935                                         unpackImage(ima, PF_ASK);
936                                         // XXX BIF_undo_push("Unpack image");
937                                 }
938                         }
939                         else {
940                                 ImBuf *ibuf= get_space_image_buffer(sima);
941                                 if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) {
942                                         if(1) // XXX okee("Can't pack painted image. Use Repack as PNG?"))
943                                                 BKE_image_memorypack(ima);
944                                 }
945                                 else {
946                                         ima->packedfile = newPackedFile(ima->name);
947                                         // XXX BIF_undo_push("Pack image");
948                                 }
949                         }
950
951                         // XXX allqueue(REDRAWBUTSSHADING, 0);
952                         // XXX allqueue(REDRAWHEADERS, 0);
953                 }
954         }
955 }
956
957 /* XXX notifier? */
958 #if 0
959 /* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
960 void BIF_image_update_frame(void)
961 {
962         Tex *tex;
963         
964         /* texture users */
965         for(tex= G.main->tex.first; tex; tex= tex->id.next) {
966                 if(tex->type==TEX_IMAGE && tex->ima)
967                         if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
968                                 if(tex->iuser.flag & IMA_ANIM_ALWAYS)
969                                         BKE_image_user_calc_imanr(&tex->iuser, scene->r.cfra, 0);
970                 
971         }
972         /* image window, compo node users */
973         if(G.curscreen) {
974                 ScrArea *sa;
975                 for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
976                         if(sa->spacetype==SPACE_VIEW3D) {
977                                 View3D *v3d= sa->spacedata.first;
978                                 if(v3d->bgpic)
979                                         if(v3d->bgpic->iuser.flag & IMA_ANIM_ALWAYS)
980                                                 BKE_image_user_calc_imanr(&v3d->bgpic->iuser, scene->r.cfra, 0);
981                         }
982                         else if(sa->spacetype==SPACE_IMAGE) {
983                                 SpaceImage *sima= sa->spacedata.first;
984                                 if(sima->iuser.flag & IMA_ANIM_ALWAYS)
985                                         BKE_image_user_calc_imanr(&sima->iuser, scene->r.cfra, 0);
986                         }
987                         else if(sa->spacetype==SPACE_NODE) {
988                                 SpaceNode *snode= sa->spacedata.first;
989                                 if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
990                                         bNode *node;
991                                         for(node= snode->nodetree->nodes.first; node; node= node->next) {
992                                                 if(node->id && node->type==CMP_NODE_IMAGE) {
993                                                         Image *ima= (Image *)node->id;
994                                                         ImageUser *iuser= node->storage;
995                                                         if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
996                                                                 if(iuser->flag & IMA_ANIM_ALWAYS)
997                                                                         BKE_image_user_calc_imanr(iuser, scene->r.cfra, 0);
998                                                 }
999                                         }
1000                                 }
1001                         }
1002                 }
1003         }
1004 }
1005 #endif
1006
1007 void image_pixel_aspect(Image *image, float *x, float *y)
1008 {
1009         *x = *y = 1.0;
1010         
1011         if(             (image == NULL) ||
1012                         (image->type == IMA_TYPE_R_RESULT) ||
1013                         (image->type == IMA_TYPE_COMPOSITE) ||
1014                         (image->tpageflag & IMA_TILES) ||
1015                         (image->aspx==0.0 || image->aspy==0.0)
1016         ) {
1017                 return;
1018         }
1019         
1020         /* x is always 1 */
1021         *y = image->aspy / image->aspx;
1022 }
1023
1024 void image_final_aspect(Image *image, float *x, float *y)
1025 {
1026         *x = *y = 1.0;
1027         
1028         if(             (image == NULL) ||
1029                         (image->type == IMA_TYPE_R_RESULT) ||
1030                         (image->type == IMA_TYPE_COMPOSITE) ||
1031                         (image->tpageflag & IMA_TILES) ||
1032                         (image->aspx==0.0 || image->aspy==0.0)
1033         ) {
1034                 return;
1035         } else {
1036                 ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
1037                 if (ibuf && ibuf->x && ibuf->y)  {
1038                         *y = (image->aspy * ibuf->y) / (image->aspx * ibuf->x);
1039                 } else {
1040                         /* x is always 1 */
1041                         *y = image->aspy / image->aspx;
1042                 }
1043         }
1044 }
1045
1046 void sima_sample_color(SpaceImage *sima)
1047 {
1048         ImBuf *ibuf= get_space_image_buffer(sima);
1049         float fx, fy;
1050         short mval[2], mvalo[2], firsttime=1;
1051         
1052         if(ibuf==NULL)
1053                 return;
1054         
1055         // XXX calc_image_view(sima, 'f');
1056         // XXX getmouseco_areawin(mvalo);
1057         
1058         while(0) { // XXX get_mbut() & L_MOUSE) {
1059                 
1060                 // XXX getmouseco_areawin(mval);
1061                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
1062                         firsttime= 0;
1063                         // XXX areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
1064                         
1065                         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1066                                 float *fp= NULL, *zpf= NULL;
1067                                 float vec[3];
1068                                 int *zp= NULL;
1069                                 char *cp= NULL;
1070                                 
1071                                 int x= (int) (fx*ibuf->x);
1072                                 int y= (int) (fy*ibuf->y);
1073                                 
1074                                 if(x>=ibuf->x) x= ibuf->x-1;
1075                                 if(y>=ibuf->y) y= ibuf->y-1;
1076                                 
1077                                 if(ibuf->rect)
1078                                         cp= (char *)(ibuf->rect + y*ibuf->x + x);
1079                                 if(ibuf->zbuf)
1080                                         zp= ibuf->zbuf + y*ibuf->x + x;
1081                                 if(ibuf->zbuf_float)
1082                                         zpf= ibuf->zbuf_float + y*ibuf->x + x;
1083                                 if(ibuf->rect_float)
1084                                         fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1085                                         
1086                                 if(fp==NULL) {
1087                                         fp= vec;
1088                                         vec[0]= (float)cp[0]/255.0f;
1089                                         vec[1]= (float)cp[1]/255.0f;
1090                                         vec[2]= (float)cp[2]/255.0f;
1091                                 }
1092                                 
1093                                 if(sima->cumap) {
1094                                         
1095                                         if(ibuf->channels==4) {
1096                                                 if(0) { // XXX G.qual & LR_CTRLKEY) {
1097                                                         curvemapping_set_black_white(sima->cumap, NULL, fp);
1098                                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1099                                                 }
1100                                                 else if(0) { // XXX G.qual & LR_SHIFTKEY) {
1101                                                         curvemapping_set_black_white(sima->cumap, fp, NULL);
1102                                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1103                                                 }
1104                                         }
1105                                 }
1106                                 
1107 #if 0
1108                                 {
1109                                         ScrArea *sa, *cur= curarea;
1110                                         
1111                                         node_curvemap_sample(fp);       /* sends global to node editor */
1112                                         for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1113                                                 if(sa->spacetype==SPACE_NODE) {
1114                                                         areawinset(sa->win);
1115                                                         scrarea_do_windraw(sa);
1116                                                 }
1117                                         }
1118                                         node_curvemap_sample(NULL);             /* clears global in node editor */
1119                                         curarea= cur;
1120                                 }
1121                                 
1122                                 areawinset(curarea->win);
1123                                 scrarea_do_windraw(curarea);
1124                                 myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
1125                                 glLoadIdentity();
1126                                 
1127                                 sima_show_info(ibuf->channels, x, y, cp, (ibuf->rect_float)?fp:NULL, zp, zpf);
1128                                 
1129                                 screen_swapbuffers();
1130 #endif
1131                                 
1132                         }
1133                 }
1134                 // XXX BIF_wait_for_statechange();
1135         }
1136         
1137         // XXX scrarea_queue_winredraw(curarea);
1138 }
1139
1140 void mouseco_to_curtile(SpaceImage *sima, struct Object *obedit)
1141 {
1142         float fx, fy;
1143         short mval[2];
1144         int show_uvedit;
1145         
1146         show_uvedit= get_space_image_show_uvedit(sima, obedit);
1147         if(!show_uvedit) return;
1148
1149         if(sima->image && sima->image->tpageflag & IMA_TILES) {
1150                 
1151                 sima->flag |= SI_EDITTILE;
1152                 
1153                 while(0) { // XXX get_mbut()&L_MOUSE) {
1154                         
1155                         // XXX calc_image_view(sima, 'f');
1156                         
1157                         // XXX getmouseco_areawin(mval);
1158                         // XXX areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
1159
1160                         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1161                         
1162                                 fx= (fx)*sima->image->xrep;
1163                                 fy= (fy)*sima->image->yrep;
1164                                 
1165                                 mval[0]= fx;
1166                                 mval[1]= fy;
1167                                 
1168                                 sima->curtile= mval[1]*sima->image->xrep + mval[0];
1169                         }
1170
1171                         // XXX scrarea_do_windraw(curarea);
1172                         // XXX screen_swapbuffers();
1173                 }
1174                 
1175                 sima->flag &= ~SI_EDITTILE;
1176
1177                 // XXX image_set_tile(sima, 2);
1178
1179                 // XXX allqueue(REDRAWVIEW3D, 0);
1180                 // XXX scrarea_queue_winredraw(curarea);
1181         }
1182 }
1183
1184 /* Could be used for other 2D views also */
1185 void mouseco_to_cursor_sima(void)
1186 {
1187         // XXX short mval[2];
1188         // XXX getmouseco_areawin(mval);
1189         // XXX areamouseco_to_ipoco(G.v2d, mval, &G.v2d->cursor[0], &G.v2d->cursor[1]);
1190         // XXX scrarea_queue_winredraw(curarea);
1191 }
1192