2.5: Space Image ported back
[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 static 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         PropertyRNA *prop;
260
261         /* identifiers */
262         ot->name= "View Pan";
263         ot->idname= "IMAGE_OT_view_pan";
264         
265         /* api callbacks */
266         ot->exec= view_pan_exec;
267         ot->invoke= view_pan_invoke;
268         ot->modal= view_pan_modal;
269         ot->cancel= view_pan_cancel;
270         ot->poll= space_image_main_area_poll;
271
272         /* properties */
273         prop= RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_VECTOR);
274         RNA_def_property_array(prop, 2);
275         RNA_def_property_ui_text(prop, "Offset", "Offset in floating point units, 1.0 is the width and height of the image.");
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         PropertyRNA *prop;
375
376         /* identifiers */
377         ot->name= "View Zoom";
378         ot->idname= "IMAGE_OT_view_zoom";
379         
380         /* api callbacks */
381         ot->exec= view_zoom_exec;
382         ot->invoke= view_zoom_invoke;
383         ot->modal= view_zoom_modal;
384         ot->cancel= view_zoom_cancel;
385         ot->poll= space_image_main_area_poll;
386
387         /* properties */
388         prop= RNA_def_property(ot->srna, "factor", PROP_FLOAT, PROP_UNSIGNED);
389         RNA_def_property_ui_text(prop, "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.");
390 }
391
392 /********************** view all operator *********************/
393
394 /* Updates the fields of the View2D member of the SpaceImage struct.
395  * Default behavior is to reset the position of the image and set the zoom to 1
396  * If the image will not fit within the window rectangle, the zoom is adjusted */
397
398 static int view_all_exec(bContext *C, wmOperator *op)
399 {
400         SpaceImage *sima;
401         ARegion *ar;
402         Scene *scene;
403         Object *obedit;
404         Image *ima;
405         ImBuf *ibuf;
406         float aspx, aspy, zoomx, zoomy, w, h;
407         int width, height;
408
409         /* retrieve state */
410         sima= (SpaceImage*)CTX_wm_space_data(C);
411         ar= CTX_wm_region(C);
412         scene= (Scene*)CTX_data_scene(C);
413         obedit= CTX_data_edit_object(C);
414
415         ima= get_space_image(sima);
416         ibuf= get_space_image_buffer(sima);
417         get_space_image_size(sima, &width, &height);
418         get_space_image_aspect(sima, &aspx, &aspy);
419
420         w= width*aspx;
421         h= height*aspy;
422         
423         /* check if the image will fit in the image with zoom==1 */
424         width = ar->winrct.xmax - ar->winrct.xmin + 1;
425         height = ar->winrct.ymax - ar->winrct.ymin + 1;
426
427         if((w >= width || h >= height) && (width > 0 && height > 0)) {
428                 /* find the zoom value that will fit the image in the image space */
429                 zoomx= width/w;
430                 zoomy= height/h;
431                 sima_zoom_set(sima, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy)));
432         }
433         else
434                 sima_zoom_set(sima, ar, 1.0f);
435
436         sima->xof= sima->yof= 0.0f;
437
438         ED_area_tag_redraw(CTX_wm_area(C));
439         
440         return OPERATOR_FINISHED;
441 }
442
443 void IMAGE_OT_view_all(wmOperatorType *ot)
444 {
445         /* identifiers */
446         ot->name= "View All";
447         ot->idname= "IMAGE_OT_view_all";
448         
449         /* api callbacks */
450         ot->exec= view_all_exec;
451         ot->poll= space_image_main_area_poll;
452 }
453
454 /********************** view selected operator *********************/
455
456 static int view_selected_exec(bContext *C, wmOperator *op)
457 {
458         SpaceImage *sima;
459         ARegion *ar;
460         Scene *scene;
461         Object *obedit;
462         Image *ima;
463         ImBuf *ibuf;
464         float size, min[2], max[2], d[2];
465         int width, height;
466
467         /* retrieve state */
468         sima= (SpaceImage*)CTX_wm_space_data(C);
469         ar= CTX_wm_region(C);
470         scene= (Scene*)CTX_data_scene(C);
471         obedit= CTX_data_edit_object(C);
472
473         ima= get_space_image(sima);
474         ibuf= get_space_image_buffer(sima);
475         get_space_image_size(sima, &width, &height);
476
477         /* get bounds */
478         if(!ED_uvedit_minmax(scene, ima, obedit, min, max))
479                 return OPERATOR_CANCELLED;
480
481         /* adjust offset and zoom */
482         sima->xof= (int)(((min[0] + max[0])*0.5f - 0.5f)*width);
483         sima->yof= (int)(((min[1] + max[1])*0.5f - 0.5f)*height);
484
485         d[0]= max[0] - min[0];
486         d[1]= max[1] - min[1];
487         size= 0.5*MAX2(d[0], d[1])*MAX2(width, height)/256.0f;
488         
489         if(size<=0.01) size= 0.01;
490         sima_zoom_set(sima, ar, 0.7/size);
491
492         ED_area_tag_redraw(CTX_wm_area(C));
493         
494         return OPERATOR_FINISHED;
495 }
496
497 void IMAGE_OT_view_selected(wmOperatorType *ot)
498 {
499         /* identifiers */
500         ot->name= "View Center";
501         ot->idname= "IMAGE_OT_view_selected";
502         
503         /* api callbacks */
504         ot->exec= view_selected_exec;
505         ot->poll= ED_operator_uvedit;
506 }
507
508 /********************** view zoom in/out operator *********************/
509
510 static int view_zoom_in_exec(bContext *C, wmOperator *op)
511 {
512         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
513         ARegion *ar= CTX_wm_region(C);
514
515         sima_zoom_set_factor(sima, ar, 1.25f);
516
517         ED_area_tag_redraw(CTX_wm_area(C));
518         
519         return OPERATOR_FINISHED;
520 }
521
522 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
523 {
524         /* identifiers */
525         ot->name= "View Zoom In";
526         ot->idname= "IMAGE_OT_view_zoom_in";
527         
528         /* api callbacks */
529         ot->exec= view_zoom_in_exec;
530         ot->poll= space_image_main_area_poll;
531 }
532
533 static int view_zoom_out_exec(bContext *C, wmOperator *op)
534 {
535         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
536         ARegion *ar= CTX_wm_region(C);
537
538         sima_zoom_set_factor(sima, ar, 0.8f);
539
540         ED_area_tag_redraw(CTX_wm_area(C));
541         
542         return OPERATOR_FINISHED;
543 }
544
545 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
546 {
547         /* identifiers */
548         ot->name= "View Zoom Out";
549         ot->idname= "IMAGE_OT_view_zoom_out";
550         
551         /* api callbacks */
552         ot->exec= view_zoom_out_exec;
553         ot->poll= space_image_main_area_poll;
554 }
555
556 /********************** view zoom ratio operator *********************/
557
558 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
559 {
560         SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
561         ARegion *ar= CTX_wm_region(C);
562
563         sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"));
564         
565         /* ensure pixel exact locations for draw */
566         sima->xof= (int)sima->xof;
567         sima->yof= (int)sima->yof;
568
569         /* XXX notifier? */
570 #if 0
571         if(image_preview_active(curarea, NULL, NULL)) {
572                 /* recalculates new preview rect */
573                 scrarea_do_windraw(curarea);
574                 image_preview_event(2);
575         }
576 #endif
577
578         ED_area_tag_redraw(CTX_wm_area(C));
579         
580         return OPERATOR_FINISHED;
581 }
582
583 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
584 {
585         PropertyRNA *prop;
586
587         /* identifiers */
588         ot->name= "View Zoom Ratio";
589         ot->idname= "IMAGE_OT_view_zoom_ratio";
590         
591         /* api callbacks */
592         ot->exec= view_zoom_ratio_exec;
593         ot->poll= space_image_main_area_poll;
594         
595         /* properties */
596         prop= RNA_def_property(ot->srna, "ratio", PROP_FLOAT, PROP_UNSIGNED);
597         RNA_def_property_ui_text(prop, "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out.");
598 }
599
600 /* Image functions */
601
602 #if 0
603 static void load_image_filesel(SpaceImage *sima, Scene *scene, Object *obedit, char *str)       /* called from fileselect */
604 {
605         Image *ima= NULL;
606
607         ima= BKE_add_image_file(str, scene->r.cfra);
608         if(ima) {
609                 BKE_image_signal(ima, &sima->iuser, IMA_SIGNAL_RELOAD);
610                 set_space_image(sima, scene, obedit, ima);
611         }
612         // XXX BIF_undo_push("Load image UV");
613         // XXX allqueue(REDRAWIMAGE, 0);
614 }
615
616 static void replace_image_filesel(SpaceImage *sima, char *str)          /* called from fileselect */
617 {
618         if (!sima->image)
619                 return;
620         
621         BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
622         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
623         // XXX BIF_undo_push("Replace image UV");
624         // XXX allqueue(REDRAWIMAGE, 0);
625         // XXX allqueue(REDRAWVIEW3D, 0);
626 }
627 #endif
628
629 static void save_image_doit(SpaceImage *sima, Scene *scene, char *name)
630 {
631         Image *ima= get_space_image(sima);
632         ImBuf *ibuf= get_space_image_buffer(sima);
633         int len;
634         char str[FILE_MAXDIR+FILE_MAXFILE];
635
636         if (ibuf) {
637                 BLI_strncpy(str, name, sizeof(str));
638
639                 BLI_convertstringcode(str, G.sce);
640                 BLI_convertstringframe(str, scene->r.cfra);
641                 
642                 
643                 if(scene->r.scemode & R_EXTENSION)  {
644                         BKE_add_image_extension(scene, str, sima->imtypenr);
645                         BKE_add_image_extension(scene, name, sima->imtypenr);
646                 }
647                 
648                 if (1) { // XXX saveover(str)) {
649                         
650                         /* enforce user setting for RGB or RGBA, but skip BW */
651                         if(scene->r.planes==32)
652                                 ibuf->depth= 32;
653                         else if(scene->r.planes==24)
654                                 ibuf->depth= 24;
655                         
656                         // XXX waitcursor(1);
657                         if(sima->imtypenr==R_MULTILAYER) {
658                                 RenderResult *rr= BKE_image_get_renderresult(scene, ima);
659                                 if(rr) {
660                                         RE_WriteRenderResult(rr, str, scene->r.quality);
661                                         
662                                         BLI_strncpy(ima->name, name, sizeof(ima->name));
663                                         BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
664                                         
665                                         /* should be function? nevertheless, saving only happens here */
666                                         for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
667                                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
668                                         
669                                 }
670                                 else; // XXX error("Did not write, no Multilayer Image");
671                         }
672                         else if (BKE_write_ibuf(scene, ibuf, str, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
673                                 BLI_strncpy(ima->name, name, sizeof(ima->name));
674                                 BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
675                                 
676                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
677                                 
678                                 /* change type? */
679                                 if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
680                                         ima->source= IMA_SRC_FILE;
681                                         ima->type= IMA_TYPE_IMAGE;
682                                 }
683                                 if(ima->type==IMA_TYPE_R_RESULT)
684                                         ima->type= IMA_TYPE_IMAGE;
685                                 
686                                 /* name image as how we saved it */
687                                 len= strlen(str);
688                                 while (len > 0 && str[len - 1] != '/' && str[len - 1] != '\\') len--;
689                                 rename_id(&ima->id, str+len);
690                         } 
691                         else {
692                                 ; // XXX error("Couldn't write image: %s", str);
693                         }
694
695                         // XXX allqueue(REDRAWHEADERS, 0);
696                         // XXX allqueue(REDRAWBUTSSHADING, 0);
697
698                         // XXX waitcursor(0);
699                 }
700         }
701 }
702
703 void open_image_sima(SpaceImage *sima, short imageselect)
704 {
705         char name[FILE_MAXDIR+FILE_MAXFILE];
706
707         if(sima->image)
708                 BLI_strncpy(name, sima->image->name, sizeof(name));
709         else
710                 BLI_strncpy(name, U.textudir, sizeof(name));
711
712         if(imageselect)
713                 ; // XXX activate_imageselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
714         else
715                 ; // XXX activate_fileselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
716 }
717
718 void replace_image_sima(SpaceImage *sima, short imageselect)
719 {
720         char name[FILE_MAXDIR+FILE_MAXFILE];
721
722         if(sima->image)
723                 BLI_strncpy(name, sima->image->name, sizeof(name));
724         else
725                 BLI_strncpy(name, U.textudir, sizeof(name));
726         
727         if(imageselect)
728                 ; // XXX activate_imageselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
729         else
730                 ; // XXX activate_fileselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
731 }
732
733
734 static char *filesel_imagetype_string(Image *ima)
735 {
736         char *strp, *str= MEM_callocN(14*32, "menu for filesel");
737         
738         strp= str;
739         str += sprintf(str, "Save Image as: %%t|");
740         str += sprintf(str, "Targa %%x%d|", R_TARGA);
741         str += sprintf(str, "Targa Raw %%x%d|", R_RAWTGA);
742         str += sprintf(str, "PNG %%x%d|", R_PNG);
743         str += sprintf(str, "BMP %%x%d|", R_BMP);
744         str += sprintf(str, "Jpeg %%x%d|", R_JPEG90);
745         str += sprintf(str, "Iris %%x%d|", R_IRIS);
746         if(G.have_libtiff)
747                 str += sprintf(str, "Tiff %%x%d|", R_TIFF);
748         str += sprintf(str, "Radiance HDR %%x%d|", R_RADHDR);
749         str += sprintf(str, "Cineon %%x%d|", R_CINEON);
750         str += sprintf(str, "DPX %%x%d|", R_DPX);
751 #ifdef WITH_OPENEXR
752         str += sprintf(str, "OpenEXR %%x%d|", R_OPENEXR);
753         /* saving sequences of multilayer won't work, they copy buffers  */
754         if(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER);
755         else str += sprintf(str, "MultiLayer %%x%d|", R_MULTILAYER);
756 #endif  
757         return strp;
758 }
759
760 /* always opens fileselect */
761 void save_as_image_sima(SpaceImage *sima, Scene *scene)
762 {
763         Image *ima = sima->image;
764         ImBuf *ibuf= get_space_image_buffer(sima);
765         char name[FILE_MAXDIR+FILE_MAXFILE];
766
767         if (ima) {
768                 strcpy(name, ima->name);
769
770                 if (ibuf) {
771                         char *strp;
772                         
773                         strp= filesel_imagetype_string(ima);
774                         
775                         /* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
776                         if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
777                                 sima->imtypenr= R_MULTILAYER;
778                         else if(ima->type==IMA_TYPE_R_RESULT)
779                                 sima->imtypenr= scene->r.imtype;
780                         else sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
781                         
782                         // XXX activate_fileselect_menu(FILE_SPECIAL, "Save Image", name, strp, &sima->imtypenr, save_image_doit);
783                 }
784         }
785 }
786
787 /* if exists, saves over without fileselect */
788 void save_image_sima(SpaceImage *sima, Scene *scene)
789 {
790         Image *ima = get_space_image(sima);
791         ImBuf *ibuf= get_space_image_buffer(sima);
792         char name[FILE_MAXDIR+FILE_MAXFILE];
793
794         if (ima) {
795                 strcpy(name, ima->name);
796
797                 if (ibuf) {
798                         if (BLI_exists(ibuf->name)) {
799                                 if(BKE_image_get_renderresult(scene, ima)) 
800                                         sima->imtypenr= R_MULTILAYER;
801                                 else 
802                                         sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
803                                 
804                                 save_image_doit(sima, scene, ibuf->name);
805                         }
806                         else
807                                 save_as_image_sima(sima, scene);
808                 }
809         }
810 }
811
812 void save_image_sequence_sima(SpaceImage *sima)
813 {
814         ImBuf *ibuf;
815         int tot= 0;
816         char di[FILE_MAX], fi[FILE_MAX];
817         
818         if(sima->image==NULL)
819                 return;
820         if(sima->image->source!=IMA_SRC_SEQUENCE)
821                 return;
822         if(sima->image->type==IMA_TYPE_MULTILAYER) {
823                 // XXX error("Cannot save Multilayer Sequences");
824                 return;
825         }
826         
827         /* get total */
828         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
829                 if(ibuf->userflags & IB_BITMAPDIRTY)
830                         tot++;
831         
832         if(tot==0) {
833                 // XXX notice("No Images have been changed");
834                 return;
835         }
836         /* get a filename for menu */
837         for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 
838                 if(ibuf->userflags & IB_BITMAPDIRTY)
839                         break;
840         
841         BLI_strncpy(di, ibuf->name, FILE_MAX);
842         BLI_splitdirstring(di, fi);
843         
844         sprintf(fi, "%d Image(s) will be saved in %s", tot, di);
845         if(1) { // XXX okee(fi)) {
846                 
847                 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) {
848                         if(ibuf->userflags & IB_BITMAPDIRTY) {
849                                 char name[FILE_MAX];
850                                 BLI_strncpy(name, ibuf->name, sizeof(name));
851                                 
852                                 BLI_convertstringcode(name, G.sce);
853
854                                 if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
855                                         // XXX error("Could not write image", name);
856                                         break;
857                                 }
858                                 printf("Saved: %s\n", ibuf->name);
859                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
860                         }
861                 }
862         }
863 }
864
865 void reload_image_sima(SpaceImage *sima)
866 {
867         if (sima ) {
868                 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
869                 /* set_space_image(sima, scene, obedit, NULL); - do we really need this? */
870         }
871
872         // XXX allqueue(REDRAWIMAGE, 0);
873         // XXX allqueue(REDRAWVIEW3D, 0);
874         // XXX BIF_preview_changed(ID_TE);
875 }
876
877 void new_image_sima(SpaceImage *sima, Scene *scene, Object *obedit)
878 {
879         static int width= 1024, height= 1024;
880         static short uvtestgrid= 0;
881         static int floatbuf=0;
882         static float color[] = {0, 0, 0, 1};
883         char name[22];
884         Image *ima;
885         
886         strcpy(name, "Untitled");
887
888 #if 0
889         add_numbut(0, TEX, "Name:", 0, 21, name, NULL);
890         add_numbut(1, NUM|INT, "Width:", 1, 16384, &width, NULL);
891         add_numbut(2, NUM|INT, "Height:", 1, 16384, &height, NULL);
892         add_numbut(3, COL, "", 0, 0, &color, NULL);
893         add_numbut(4, NUM|FLO, "Alpha:", 0.0, 1.0, &color[3], NULL);
894         add_numbut(5, TOG|SHO, "UV Test Grid", 0, 0, &uvtestgrid, NULL);
895         add_numbut(6, TOG|INT, "32 bit Float", 0, 0, &floatbuf, NULL);
896         if (!do_clever_numbuts("New Image", 7, REDRAW))
897                 return;
898 #endif
899
900         ima = BKE_add_image_size(width, height, name, floatbuf, uvtestgrid, color);
901         set_space_image(sima, scene, obedit, ima);
902         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE);
903         // XXX BIF_undo_push("Add image");
904
905         // XXX allqueue(REDRAWIMAGE, 0);
906         // XXX allqueue(REDRAWVIEW3D, 0);
907 }
908
909 void pack_image_sima(SpaceImage *sima)
910 {
911         Image *ima = sima->image;
912
913         if (ima) {
914                 if(ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE) {
915                         if (ima->packedfile) {
916                                 if (G.fileflags & G_AUTOPACK)
917                                         if (1) // XXX okee("Disable AutoPack?"))
918                                                 G.fileflags &= ~G_AUTOPACK;
919                                 
920                                 if ((G.fileflags & G_AUTOPACK) == 0) {
921                                         unpackImage(ima, PF_ASK);
922                                         // XXX BIF_undo_push("Unpack image");
923                                 }
924                         }
925                         else {
926                                 ImBuf *ibuf= get_space_image_buffer(sima);
927                                 if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) {
928                                         if(1) // XXX okee("Can't pack painted image. Use Repack as PNG?"))
929                                                 BKE_image_memorypack(ima);
930                                 }
931                                 else {
932                                         ima->packedfile = newPackedFile(ima->name);
933                                         // XXX BIF_undo_push("Pack image");
934                                 }
935                         }
936
937                         // XXX allqueue(REDRAWBUTSSHADING, 0);
938                         // XXX allqueue(REDRAWHEADERS, 0);
939                 }
940         }
941 }
942
943 /* XXX notifier? */
944 #if 0
945 /* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
946 void BIF_image_update_frame(void)
947 {
948         Tex *tex;
949         
950         /* texture users */
951         for(tex= G.main->tex.first; tex; tex= tex->id.next) {
952                 if(tex->type==TEX_IMAGE && tex->ima)
953                         if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
954                                 if(tex->iuser.flag & IMA_ANIM_ALWAYS)
955                                         BKE_image_user_calc_imanr(&tex->iuser, scene->r.cfra, 0);
956                 
957         }
958         /* image window, compo node users */
959         if(G.curscreen) {
960                 ScrArea *sa;
961                 for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
962                         if(sa->spacetype==SPACE_VIEW3D) {
963                                 View3D *v3d= sa->spacedata.first;
964                                 if(v3d->bgpic)
965                                         if(v3d->bgpic->iuser.flag & IMA_ANIM_ALWAYS)
966                                                 BKE_image_user_calc_imanr(&v3d->bgpic->iuser, scene->r.cfra, 0);
967                         }
968                         else if(sa->spacetype==SPACE_IMAGE) {
969                                 SpaceImage *sima= sa->spacedata.first;
970                                 if(sima->iuser.flag & IMA_ANIM_ALWAYS)
971                                         BKE_image_user_calc_imanr(&sima->iuser, scene->r.cfra, 0);
972                         }
973                         else if(sa->spacetype==SPACE_NODE) {
974                                 SpaceNode *snode= sa->spacedata.first;
975                                 if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
976                                         bNode *node;
977                                         for(node= snode->nodetree->nodes.first; node; node= node->next) {
978                                                 if(node->id && node->type==CMP_NODE_IMAGE) {
979                                                         Image *ima= (Image *)node->id;
980                                                         ImageUser *iuser= node->storage;
981                                                         if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
982                                                                 if(iuser->flag & IMA_ANIM_ALWAYS)
983                                                                         BKE_image_user_calc_imanr(iuser, scene->r.cfra, 0);
984                                                 }
985                                         }
986                                 }
987                         }
988                 }
989         }
990 }
991 #endif
992
993 void image_pixel_aspect(Image *image, float *x, float *y)
994 {
995         *x = *y = 1.0;
996         
997         if(             (image == NULL) ||
998                         (image->type == IMA_TYPE_R_RESULT) ||
999                         (image->type == IMA_TYPE_COMPOSITE) ||
1000                         (image->tpageflag & IMA_TILES) ||
1001                         (image->aspx==0.0 || image->aspy==0.0)
1002         ) {
1003                 return;
1004         }
1005         
1006         /* x is always 1 */
1007         *y = image->aspy / image->aspx;
1008 }
1009
1010 void image_final_aspect(Image *image, float *x, float *y)
1011 {
1012         *x = *y = 1.0;
1013         
1014         if(             (image == NULL) ||
1015                         (image->type == IMA_TYPE_R_RESULT) ||
1016                         (image->type == IMA_TYPE_COMPOSITE) ||
1017                         (image->tpageflag & IMA_TILES) ||
1018                         (image->aspx==0.0 || image->aspy==0.0)
1019         ) {
1020                 return;
1021         } else {
1022                 ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
1023                 if (ibuf && ibuf->x && ibuf->y)  {
1024                         *y = (image->aspy * ibuf->y) / (image->aspx * ibuf->x);
1025                 } else {
1026                         /* x is always 1 */
1027                         *y = image->aspy / image->aspx;
1028                 }
1029         }
1030 }
1031
1032 void sima_sample_color(SpaceImage *sima)
1033 {
1034         ImBuf *ibuf= get_space_image_buffer(sima);
1035         float fx, fy;
1036         short mval[2], mvalo[2], firsttime=1;
1037         
1038         if(ibuf==NULL)
1039                 return;
1040         
1041         // XXX calc_image_view(sima, 'f');
1042         // XXX getmouseco_areawin(mvalo);
1043         
1044         while(0) { // XXX get_mbut() & L_MOUSE) {
1045                 
1046                 // XXX getmouseco_areawin(mval);
1047                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
1048                         firsttime= 0;
1049                         // XXX areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
1050                         
1051                         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1052                                 float *fp= NULL, *zpf= NULL;
1053                                 float vec[3];
1054                                 int *zp= NULL;
1055                                 char *cp= NULL;
1056                                 
1057                                 int x= (int) (fx*ibuf->x);
1058                                 int y= (int) (fy*ibuf->y);
1059                                 
1060                                 if(x>=ibuf->x) x= ibuf->x-1;
1061                                 if(y>=ibuf->y) y= ibuf->y-1;
1062                                 
1063                                 if(ibuf->rect)
1064                                         cp= (char *)(ibuf->rect + y*ibuf->x + x);
1065                                 if(ibuf->zbuf)
1066                                         zp= ibuf->zbuf + y*ibuf->x + x;
1067                                 if(ibuf->zbuf_float)
1068                                         zpf= ibuf->zbuf_float + y*ibuf->x + x;
1069                                 if(ibuf->rect_float)
1070                                         fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1071                                         
1072                                 if(fp==NULL) {
1073                                         fp= vec;
1074                                         vec[0]= (float)cp[0]/255.0f;
1075                                         vec[1]= (float)cp[1]/255.0f;
1076                                         vec[2]= (float)cp[2]/255.0f;
1077                                 }
1078                                 
1079                                 if(sima->cumap) {
1080                                         
1081                                         if(ibuf->channels==4) {
1082                                                 if(0) { // XXX G.qual & LR_CTRLKEY) {
1083                                                         curvemapping_set_black_white(sima->cumap, NULL, fp);
1084                                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1085                                                 }
1086                                                 else if(0) { // XXX G.qual & LR_SHIFTKEY) {
1087                                                         curvemapping_set_black_white(sima->cumap, fp, NULL);
1088                                                         curvemapping_do_ibuf(sima->cumap, ibuf);
1089                                                 }
1090                                         }
1091                                 }
1092                                 
1093 #if 0
1094                                 {
1095                                         ScrArea *sa, *cur= curarea;
1096                                         
1097                                         node_curvemap_sample(fp);       /* sends global to node editor */
1098                                         for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1099                                                 if(sa->spacetype==SPACE_NODE) {
1100                                                         areawinset(sa->win);
1101                                                         scrarea_do_windraw(sa);
1102                                                 }
1103                                         }
1104                                         node_curvemap_sample(NULL);             /* clears global in node editor */
1105                                         curarea= cur;
1106                                 }
1107                                 
1108                                 areawinset(curarea->win);
1109                                 scrarea_do_windraw(curarea);
1110                                 myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
1111                                 glLoadIdentity();
1112                                 
1113                                 sima_show_info(ibuf->channels, x, y, cp, (ibuf->rect_float)?fp:NULL, zp, zpf);
1114                                 
1115                                 screen_swapbuffers();
1116 #endif
1117                                 
1118                         }
1119                 }
1120                 // XXX BIF_wait_for_statechange();
1121         }
1122         
1123         // XXX scrarea_queue_winredraw(curarea);
1124 }
1125
1126 void mouseco_to_curtile(SpaceImage *sima, struct Object *obedit)
1127 {
1128         float fx, fy;
1129         short mval[2];
1130         int show_uvedit;
1131         
1132         show_uvedit= get_space_image_show_uvedit(sima, obedit);
1133         if(!show_uvedit) return;
1134
1135         if(sima->image && sima->image->tpageflag & IMA_TILES) {
1136                 
1137                 sima->flag |= SI_EDITTILE;
1138                 
1139                 while(0) { // XXX get_mbut()&L_MOUSE) {
1140                         
1141                         // XXX calc_image_view(sima, 'f');
1142                         
1143                         // XXX getmouseco_areawin(mval);
1144                         // XXX areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
1145
1146                         if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1147                         
1148                                 fx= (fx)*sima->image->xrep;
1149                                 fy= (fy)*sima->image->yrep;
1150                                 
1151                                 mval[0]= fx;
1152                                 mval[1]= fy;
1153                                 
1154                                 sima->curtile= mval[1]*sima->image->xrep + mval[0];
1155                         }
1156
1157                         // XXX scrarea_do_windraw(curarea);
1158                         // XXX screen_swapbuffers();
1159                 }
1160                 
1161                 sima->flag &= ~SI_EDITTILE;
1162
1163                 // XXX image_set_tile(sima, 2);
1164
1165                 // XXX allqueue(REDRAWVIEW3D, 0);
1166                 // XXX scrarea_queue_winredraw(curarea);
1167         }
1168 }
1169
1170 /* Could be used for other 2D views also */
1171 void mouseco_to_cursor_sima(void)
1172 {
1173         // XXX short mval[2];
1174         // XXX getmouseco_areawin(mval);
1175         // XXX areamouseco_to_ipoco(G.v2d, mval, &G.v2d->cursor[0], &G.v2d->cursor[1]);
1176         // XXX scrarea_queue_winredraw(curarea);
1177 }
1178