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