Texture painting:
[blender.git] / source / blender / editors / space_image / image_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2009, Xavier Thomas
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_image/image_ops.c
27  *  \ingroup spimage
28  */
29
30
31 #include <stddef.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <errno.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_math.h"
39 #include "BLI_blenlib.h"
40 #include "BLI_utildefines.h"
41
42 #include "BLF_translation.h"
43
44 #include "DNA_object_types.h"
45 #include "DNA_node_types.h"
46 #include "DNA_packedFile_types.h"
47 #include "DNA_scene_types.h"
48
49 #include "BKE_colortools.h"
50 #include "BKE_context.h"
51 #include "BKE_depsgraph.h"
52 #include "BKE_DerivedMesh.h"
53 #include "BKE_icons.h"
54 #include "BKE_image.h"
55 #include "BKE_global.h"
56 #include "BKE_library.h"
57 #include "BKE_main.h"
58 #include "BKE_packedFile.h"
59 #include "BKE_paint.h"
60 #include "BKE_report.h"
61 #include "BKE_screen.h"
62 #include "BKE_sound.h"
63
64 #include "GPU_draw.h"
65 #include "GPU_buffers.h"
66
67 #include "IMB_colormanagement.h"
68 #include "IMB_imbuf.h"
69 #include "IMB_imbuf_types.h"
70 #include "IMB_moviecache.h"
71
72 #include "RE_pipeline.h"
73
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76 #include "RNA_enum_types.h"
77
78 #include "ED_image.h"
79 #include "ED_paint.h"
80 #include "ED_render.h"
81 #include "ED_screen.h"
82 #include "ED_space_api.h"
83 #include "ED_uvedit.h"
84 #include "ED_util.h"
85
86 #include "UI_interface.h"
87 #include "UI_resources.h"
88 #include "UI_view2d.h"
89
90 #include "WM_api.h"
91 #include "WM_types.h"
92
93 #include "PIL_time.h"
94
95 #include "image_intern.h"
96
97 /******************** view navigation utilities *********************/
98
99 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom, const float location[2])
100 {
101         float oldzoom = sima->zoom;
102         int width, height;
103
104         sima->zoom = zoom;
105
106         if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
107                 /* check zoom limits */
108                 ED_space_image_get_size(sima, &width, &height);
109
110                 width *= sima->zoom;
111                 height *= sima->zoom;
112
113                 if ((width < 4) && (height < 4))
114                         sima->zoom = oldzoom;
115                 else if (BLI_rcti_size_x(&ar->winrct) <= sima->zoom)
116                         sima->zoom = oldzoom;
117                 else if (BLI_rcti_size_y(&ar->winrct) <= sima->zoom)
118                         sima->zoom = oldzoom;
119         }
120
121         if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) && location) {
122                 float aspx, aspy, w, h;
123
124                 ED_space_image_get_size(sima, &width, &height);
125                 ED_space_image_get_aspect(sima, &aspx, &aspy);
126
127                 w = width * aspx;
128                 h = height * aspy;
129
130                 sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
131                 sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
132         }
133 }
134
135 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac, const float location[2])
136 {
137         sima_zoom_set(sima, ar, sima->zoom * zoomfac, location);
138 }
139
140 #if 0 // currently unused
141 static int image_poll(bContext *C)
142 {
143         return (CTX_data_edit_image(C) != NULL);
144 }
145 #endif
146
147 static int space_image_buffer_exists_poll(bContext *C)
148 {
149         SpaceImage *sima = CTX_wm_space_image(C);
150         if (sima && sima->spacetype == SPACE_IMAGE)
151                 if (ED_space_image_has_buffer(sima))
152                         return 1;
153         return 0;
154 }
155
156 static int space_image_file_exists_poll(bContext *C)
157 {
158         if (space_image_buffer_exists_poll(C)) {
159                 Main *bmain = CTX_data_main(C);
160                 SpaceImage *sima = CTX_wm_space_image(C);
161                 ImBuf *ibuf;
162                 void *lock;
163                 bool ret = false;
164                 char name[FILE_MAX];
165
166                 ibuf = ED_space_image_acquire_buffer(sima, &lock);
167                 if (ibuf) {
168                         BLI_strncpy(name, ibuf->name, FILE_MAX);
169                         BLI_path_abs(name, bmain->name);
170
171                         if (BLI_exists(name) == false) {
172                                 CTX_wm_operator_poll_msg_set(C, "image file not found");
173                         }
174                         else if (!BLI_file_is_writable(name)) {
175                                 CTX_wm_operator_poll_msg_set(C, "image path can't be written to");
176                         }
177                         else {
178                                 ret = true;
179                         }
180                 }
181                 ED_space_image_release_buffer(sima, ibuf, lock);
182
183                 return ret;
184         }
185         return 0;
186 }
187
188 static int space_image_poll(bContext *C)
189 {
190         SpaceImage *sima = CTX_wm_space_image(C);
191         if (sima && sima->spacetype == SPACE_IMAGE && sima->image)
192                 return 1;
193         return 0;
194 }
195
196 int space_image_main_area_poll(bContext *C)
197 {
198         SpaceImage *sima = CTX_wm_space_image(C);
199         // XXX ARegion *ar = CTX_wm_region(C);
200
201         if (sima)
202                 return 1;  // XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW);
203         
204         return 0;
205 }
206
207 /* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode or editmode */
208 static int space_image_main_area_not_uv_brush_poll(bContext *C)
209 {
210         SpaceImage *sima = CTX_wm_space_image(C);
211         Scene *scene = CTX_data_scene(C);
212         ToolSettings *toolsettings = scene->toolsettings;
213
214         if (sima && !toolsettings->uvsculpt && !scene->obedit)
215                 return 1;
216
217         return 0;
218 }
219
220 static int image_sample_poll(bContext *C)
221 {
222         SpaceImage *sima = CTX_wm_space_image(C);
223         if (sima) {
224                 Scene *scene = CTX_data_scene(C);
225                 Object *obedit = CTX_data_edit_object(C);
226                 ToolSettings *toolsettings = scene->toolsettings;
227
228                 if (obedit) {
229                         if (ED_space_image_show_uvedit(sima, obedit) && (toolsettings->use_uv_sculpt))
230                                 return false;
231                 }
232                 else if (sima->mode != SI_MODE_VIEW) {
233                         return false;
234                 }
235
236                 return space_image_main_area_poll(C);
237         }
238         else {
239                 return false;
240         }
241 }
242 /********************** view pan operator *********************/
243
244 typedef struct ViewPanData {
245         float x, y;
246         float xof, yof;
247         int event_type;
248 } ViewPanData;
249
250 static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
251 {
252         SpaceImage *sima = CTX_wm_space_image(C);
253         ViewPanData *vpd;
254
255         op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
256         WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
257
258         vpd->x = event->x;
259         vpd->y = event->y;
260         vpd->xof = sima->xof;
261         vpd->yof = sima->yof;
262         vpd->event_type = event->type;
263
264         WM_event_add_modal_handler(C, op);
265 }
266
267 static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
268 {
269         SpaceImage *sima = CTX_wm_space_image(C);
270         ViewPanData *vpd = op->customdata;
271
272         if (cancel) {
273                 sima->xof = vpd->xof;
274                 sima->yof = vpd->yof;
275                 ED_region_tag_redraw(CTX_wm_region(C));
276         }
277
278         WM_cursor_modal_restore(CTX_wm_window(C));
279         MEM_freeN(op->customdata);
280 }
281
282 static int image_view_pan_exec(bContext *C, wmOperator *op)
283 {
284         SpaceImage *sima = CTX_wm_space_image(C);
285         float offset[2];
286
287         RNA_float_get_array(op->ptr, "offset", offset);
288         sima->xof += offset[0];
289         sima->yof += offset[1];
290
291         ED_region_tag_redraw(CTX_wm_region(C));
292
293         /* XXX notifier? */
294 #if 0
295         if (image_preview_active(curarea, NULL, NULL)) {
296                 /* recalculates new preview rect */
297                 scrarea_do_windraw(curarea);
298                 image_preview_event(2);
299         }
300 #endif
301         
302         return OPERATOR_FINISHED;
303 }
304
305 static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
306 {
307         if (event->type == MOUSEPAN) {
308                 SpaceImage *sima = CTX_wm_space_image(C);
309                 float offset[2];
310                 
311                 offset[0] = (event->prevx - event->x) / sima->zoom;
312                 offset[1] = (event->prevy - event->y) / sima->zoom;
313                 RNA_float_set_array(op->ptr, "offset", offset);
314
315                 image_view_pan_exec(C, op);
316                 return OPERATOR_FINISHED;
317         }
318         else {
319                 image_view_pan_init(C, op, event);
320                 return OPERATOR_RUNNING_MODAL;
321         }
322 }
323
324 static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
325 {
326         SpaceImage *sima = CTX_wm_space_image(C);
327         ViewPanData *vpd = op->customdata;
328         float offset[2];
329
330         switch (event->type) {
331                 case MOUSEMOVE:
332                         sima->xof = vpd->xof;
333                         sima->yof = vpd->yof;
334                         offset[0] = (vpd->x - event->x) / sima->zoom;
335                         offset[1] = (vpd->y - event->y) / sima->zoom;
336                         RNA_float_set_array(op->ptr, "offset", offset);
337                         image_view_pan_exec(C, op);
338                         break;
339                 default:
340                         if (event->type == vpd->event_type && event->val == KM_RELEASE) {
341                                 image_view_pan_exit(C, op, false);
342                                 return OPERATOR_FINISHED;
343                         }
344                         break;
345         }
346
347         return OPERATOR_RUNNING_MODAL;
348 }
349
350 static void image_view_pan_cancel(bContext *C, wmOperator *op)
351 {
352         image_view_pan_exit(C, op, true);
353 }
354
355 void IMAGE_OT_view_pan(wmOperatorType *ot)
356 {
357         /* identifiers */
358         ot->name = "View Pan";
359         ot->idname = "IMAGE_OT_view_pan";
360         ot->description = "Pan the view";
361         
362         /* api callbacks */
363         ot->exec = image_view_pan_exec;
364         ot->invoke = image_view_pan_invoke;
365         ot->modal = image_view_pan_modal;
366         ot->cancel = image_view_pan_cancel;
367         ot->poll = space_image_main_area_poll;
368
369         /* flags */
370         ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
371         
372         /* properties */
373         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
374                              "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
375 }
376
377 /********************** view zoom operator *********************/
378
379 typedef struct ViewZoomData {
380         float origx, origy;
381         float zoom;
382         int event_type;
383         float location[2];
384
385         /* needed for continuous zoom */
386         wmTimer *timer;
387         double timer_lastdraw;
388
389         /* */
390         SpaceImage *sima;
391         ARegion *ar;
392 } ViewZoomData;
393
394 static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
395 {
396         SpaceImage *sima = CTX_wm_space_image(C);
397         ARegion *ar = CTX_wm_region(C);
398         ViewZoomData *vpd;
399
400         op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
401         WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
402
403         vpd->origx = event->x;
404         vpd->origy = event->y;
405         vpd->zoom = sima->zoom;
406         vpd->event_type = event->type;
407
408         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
409
410         if (U.viewzoom == USER_ZOOM_CONT) {
411                 /* needs a timer to continue redrawing */
412                 vpd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
413                 vpd->timer_lastdraw = PIL_check_seconds_timer();
414         }
415
416         vpd->sima = sima;
417         vpd->ar = ar;
418
419         WM_event_add_modal_handler(C, op);
420 }
421
422 static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
423 {
424         SpaceImage *sima = CTX_wm_space_image(C);
425         ViewZoomData *vpd = op->customdata;
426
427         if (cancel) {
428                 sima->zoom = vpd->zoom;
429                 ED_region_tag_redraw(CTX_wm_region(C));
430         }
431
432         if (vpd->timer)
433                 WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
434
435         WM_cursor_modal_restore(CTX_wm_window(C));
436         MEM_freeN(op->customdata);
437 }
438
439 static int image_view_zoom_exec(bContext *C, wmOperator *op)
440 {
441         SpaceImage *sima = CTX_wm_space_image(C);
442         ARegion *ar = CTX_wm_region(C);
443
444         sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"), NULL);
445
446         ED_region_tag_redraw(ar);
447
448         /* XXX notifier? */
449 #if 0
450         if (image_preview_active(curarea, NULL, NULL)) {
451                 /* recalculates new preview rect */
452                 scrarea_do_windraw(curarea);
453                 image_preview_event(2);
454         }
455 #endif
456         
457         return OPERATOR_FINISHED;
458 }
459
460 enum {
461         VIEW_PASS = 0,
462         VIEW_APPLY,
463         VIEW_CONFIRM
464 };
465
466 static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
467 {
468         if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
469                 SpaceImage *sima = CTX_wm_space_image(C);
470                 ARegion *ar = CTX_wm_region(C);
471                 float delta, factor, location[2];
472
473                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
474
475                 delta = event->prevx - event->x + event->prevy - event->y;
476
477                 if (U.uiflag & USER_ZOOM_INVERT)
478                         delta *= -1;
479
480                 factor = 1.0f + delta / 300.0f;
481                 RNA_float_set(op->ptr, "factor", factor);
482                 sima_zoom_set(sima, ar, sima->zoom * factor, location);
483                 ED_region_tag_redraw(ar);
484                 
485                 return OPERATOR_FINISHED;
486         }
487         else {
488                 image_view_zoom_init(C, op, event);
489                 return OPERATOR_RUNNING_MODAL;
490         }
491 }
492
493 static void image_zoom_apply(ViewZoomData *vpd, wmOperator *op, const int x, const int y, const short viewzoom, const short zoom_invert)
494 {
495         float factor;
496
497         if (viewzoom == USER_ZOOM_CONT) {
498                 double time = PIL_check_seconds_timer();
499                 float time_step = (float)(time - vpd->timer_lastdraw);
500                 float fac;
501                 float zfac;
502
503                 if (U.uiflag & USER_ZOOM_HORIZ) {
504                         fac = (float)(x - vpd->origx);
505                 }
506                 else {
507                         fac = (float)(y - vpd->origy);
508                 }
509
510                 if (zoom_invert) {
511                         fac = -fac;
512                 }
513
514                 /* oldstyle zoom */
515                 zfac = 1.0f + ((fac / 20.0f) * time_step);
516                 vpd->timer_lastdraw = time;
517                 /* this is the final zoom, but instead make it into a factor */
518                 //zoom = vpd->sima->zoom * zfac;
519                 factor = (vpd->sima->zoom * zfac) / vpd->zoom;
520         }
521         else {
522                 /* for now do the same things for scale and dolly */
523                 float delta = x - vpd->origx + y - vpd->origy;
524
525                 if (zoom_invert)
526                         delta *= -1.0f;
527
528                 factor = 1.0f + delta / 300.0f;
529         }
530
531         RNA_float_set(op->ptr, "factor", factor);
532         sima_zoom_set(vpd->sima, vpd->ar, vpd->zoom * factor, vpd->location);
533         ED_region_tag_redraw(vpd->ar);
534 }
535
536 static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
537 {
538         ViewZoomData *vpd = op->customdata;
539         short event_code = VIEW_PASS;
540
541         /* execute the events */
542         if (event->type == TIMER && event->customdata == vpd->timer) {
543                 /* continuous zoom */
544                 event_code = VIEW_APPLY;
545         }
546         else if (event->type == MOUSEMOVE) {
547                 event_code = VIEW_APPLY;
548         }
549         else if (event->type == vpd->event_type && event->val == KM_RELEASE) {
550                 event_code = VIEW_CONFIRM;
551         }
552
553         if (event_code == VIEW_APPLY) {
554                 image_zoom_apply(vpd, op, event->x, event->y, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
555         }
556         else if (event_code == VIEW_CONFIRM) {
557                 image_view_zoom_exit(C, op, false);
558                 return OPERATOR_FINISHED;
559         }
560
561         return OPERATOR_RUNNING_MODAL;
562 }
563
564 static void image_view_zoom_cancel(bContext *C, wmOperator *op)
565 {
566         image_view_zoom_exit(C, op, true);
567 }
568
569 void IMAGE_OT_view_zoom(wmOperatorType *ot)
570 {
571         PropertyRNA *prop;
572
573         /* identifiers */
574         ot->name = "View Zoom";
575         ot->idname = "IMAGE_OT_view_zoom";
576         ot->description = "Zoom in/out the image";
577         
578         /* api callbacks */
579         ot->exec = image_view_zoom_exec;
580         ot->invoke = image_view_zoom_invoke;
581         ot->modal = image_view_zoom_modal;
582         ot->cancel = image_view_zoom_cancel;
583         ot->poll = space_image_main_area_poll;
584
585         /* flags */
586         ot->flag = OPTYPE_BLOCKING | OPTYPE_LOCK_BYPASS;
587         
588         /* properties */
589         prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
590                              "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
591         RNA_def_property_flag(prop, PROP_HIDDEN);
592 }
593
594 /********************** NDOF operator *********************/
595
596 /* Combined pan/zoom from a 3D mouse device.
597  * Z zooms, XY pans
598  * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
599  * that explains the negative signs in the code below
600  */
601
602 static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
603 {
604         if (event->type != NDOF_MOTION)
605                 return OPERATOR_CANCELLED;
606         else {
607                 SpaceImage *sima = CTX_wm_space_image(C);
608                 ARegion *ar = CTX_wm_region(C);
609                 float pan_vec[3];
610
611                 const wmNDOFMotionData *ndof = event->customdata;
612                 const float speed = NDOF_PIXELS_PER_SECOND;
613
614                 WM_event_ndof_pan_get(ndof, pan_vec, true);
615
616                 mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom);
617                 pan_vec[2] *= -ndof->dt;
618
619                 sima_zoom_set_factor(sima, ar, 1.0f + pan_vec[2], NULL);
620                 sima->xof += pan_vec[0];
621                 sima->yof += pan_vec[1];
622
623                 ED_region_tag_redraw(ar);
624
625                 return OPERATOR_FINISHED;
626         }
627 }
628
629 void IMAGE_OT_view_ndof(wmOperatorType *ot)
630 {
631         /* identifiers */
632         ot->name = "NDOF Pan/Zoom";
633         ot->idname = "IMAGE_OT_view_ndof";
634         ot->description = "Use a 3D mouse device to pan/zoom the view";
635         
636         /* api callbacks */
637         ot->invoke = image_view_ndof_invoke;
638         ot->poll = space_image_main_area_poll;
639
640         /* flags */
641         ot->flag = OPTYPE_LOCK_BYPASS;
642 }
643
644 /********************** view all operator *********************/
645
646 /* Updates the fields of the View2D member of the SpaceImage struct.
647  * Default behavior is to reset the position of the image and set the zoom to 1
648  * If the image will not fit within the window rectangle, the zoom is adjusted */
649
650 static int image_view_all_exec(bContext *C, wmOperator *op)
651 {
652         SpaceImage *sima;
653         ARegion *ar;
654         float aspx, aspy, zoomx, zoomy, w, h;
655         int width, height;
656         const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
657
658         /* retrieve state */
659         sima = CTX_wm_space_image(C);
660         ar = CTX_wm_region(C);
661
662         ED_space_image_get_size(sima, &width, &height);
663         ED_space_image_get_aspect(sima, &aspx, &aspy);
664
665         w = width * aspx;
666         h = height * aspy;
667         
668         /* check if the image will fit in the image with (zoom == 1) */
669         width  = BLI_rcti_size_x(&ar->winrct) + 1;
670         height = BLI_rcti_size_y(&ar->winrct) + 1;
671
672         if (fit_view) {
673                 const int margin = 5; /* margin from border */
674
675                 zoomx = (float) width / (w + 2 * margin);
676                 zoomy = (float) height / (h + 2 * margin);
677
678                 sima_zoom_set(sima, ar, min_ff(zoomx, zoomy), NULL);
679         }
680         else {
681                 if ((w >= width || h >= height) && (width > 0 && height > 0)) {
682                         zoomx = (float) width / w;
683                         zoomy = (float) height / h;
684
685                         /* find the zoom value that will fit the image in the image space */
686                         sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL);
687                 }
688                 else
689                         sima_zoom_set(sima, ar, 1.0f, NULL);
690         }
691
692         sima->xof = sima->yof = 0.0f;
693
694         ED_region_tag_redraw(ar);
695         
696         return OPERATOR_FINISHED;
697 }
698
699 void IMAGE_OT_view_all(wmOperatorType *ot)
700 {
701         PropertyRNA *prop;
702
703         /* identifiers */
704         ot->name = "View All";
705         ot->idname = "IMAGE_OT_view_all";
706         ot->description = "View the entire image";
707         
708         /* api callbacks */
709         ot->exec = image_view_all_exec;
710         ot->poll = space_image_main_area_poll;
711
712         /* properties */
713         prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
714         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
715 }
716
717 /********************** view selected operator *********************/
718
719 static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
720 {
721         SpaceImage *sima;
722         ARegion *ar;
723         Scene *scene;
724         Object *obedit;
725         Image *ima;
726         float size, min[2], max[2], d[2], aspx, aspy;
727         int width, height;
728
729         /* retrieve state */
730         sima = CTX_wm_space_image(C);
731         ar = CTX_wm_region(C);
732         scene = CTX_data_scene(C);
733         obedit = CTX_data_edit_object(C);
734
735         ima = ED_space_image(sima);
736         ED_space_image_get_size(sima, &width, &height);
737         ED_space_image_get_aspect(sima, &aspx, &aspy);
738
739         width = width * aspx;
740         height = height * aspy;
741
742         /* get bounds */
743         if (!ED_uvedit_minmax(scene, ima, obedit, min, max))
744                 return OPERATOR_CANCELLED;
745
746         /* adjust offset and zoom */
747         sima->xof = (int)(((min[0] + max[0]) * 0.5f - 0.5f) * width);
748         sima->yof = (int)(((min[1] + max[1]) * 0.5f - 0.5f) * height);
749
750         d[0] = max[0] - min[0];
751         d[1] = max[1] - min[1];
752         size = 0.5f * MAX2(d[0], d[1]) * MAX2(width, height) / 256.0f;
753         
754         if (size <= 0.01f) size = 0.01f;
755         sima_zoom_set(sima, ar, 0.7f / size, NULL);
756
757         ED_region_tag_redraw(ar);
758         
759         return OPERATOR_FINISHED;
760 }
761
762 static int image_view_selected_poll(bContext *C)
763 {
764         return (space_image_main_area_poll(C) && ED_operator_uvedit(C));
765 }
766
767 void IMAGE_OT_view_selected(wmOperatorType *ot)
768 {
769         /* identifiers */
770         ot->name = "View Center";
771         ot->idname = "IMAGE_OT_view_selected";
772         ot->description = "View all selected UVs";
773         
774         /* api callbacks */
775         ot->exec = image_view_selected_exec;
776         ot->poll = image_view_selected_poll;
777 }
778
779 /********************** view zoom in/out operator *********************/
780
781 static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
782 {
783         SpaceImage *sima = CTX_wm_space_image(C);
784         ARegion *ar = CTX_wm_region(C);
785         float location[2];
786         
787         RNA_float_get_array(op->ptr, "location", location);
788
789         sima_zoom_set_factor(sima, ar, powf(2.0f, 1.0f / 3.0f), location);
790
791         ED_region_tag_redraw(ar);
792         
793         return OPERATOR_FINISHED;
794 }
795
796 static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
797 {
798         ARegion *ar = CTX_wm_region(C);
799         float location[2];
800
801         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
802         RNA_float_set_array(op->ptr, "location", location);
803
804         return image_view_zoom_in_exec(C, op);
805 }
806
807 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
808 {
809         PropertyRNA *prop;
810
811         /* identifiers */
812         ot->name = "View Zoom In";
813         ot->idname = "IMAGE_OT_view_zoom_in";
814         ot->description = "Zoom in the image (centered around 2D cursor)";
815         
816         /* api callbacks */
817         ot->invoke = image_view_zoom_in_invoke;
818         ot->exec = image_view_zoom_in_exec;
819         ot->poll = space_image_main_area_poll;
820
821         /* flags */
822         ot->flag = OPTYPE_LOCK_BYPASS;
823
824         /* properties */
825         prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
826                                     "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
827         RNA_def_property_flag(prop, PROP_HIDDEN);
828 }
829
830 static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
831 {
832         SpaceImage *sima = CTX_wm_space_image(C);
833         ARegion *ar = CTX_wm_region(C);
834         float location[2];
835         
836         RNA_float_get_array(op->ptr, "location", location);
837
838         sima_zoom_set_factor(sima, ar, powf(0.5f, 1.0f / 3.0f), location);
839         
840         ED_region_tag_redraw(ar);
841         
842         return OPERATOR_FINISHED;
843 }
844
845 static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
846 {
847         ARegion *ar = CTX_wm_region(C);
848         float location[2];
849
850         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
851         RNA_float_set_array(op->ptr, "location", location);
852
853         return image_view_zoom_out_exec(C, op);
854 }
855
856 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
857 {
858         PropertyRNA *prop;
859
860         /* identifiers */
861         ot->name = "View Zoom Out";
862         ot->idname = "IMAGE_OT_view_zoom_out";
863         ot->description = "Zoom out the image (centered around 2D cursor)";
864         
865         /* api callbacks */
866         ot->invoke = image_view_zoom_out_invoke;
867         ot->exec = image_view_zoom_out_exec;
868         ot->poll = space_image_main_area_poll;
869
870         /* flags */
871         ot->flag = OPTYPE_LOCK_BYPASS;
872
873         /* properties */
874         prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
875                                     "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
876         RNA_def_property_flag(prop, PROP_HIDDEN);
877 }
878
879 /********************** view zoom ratio operator *********************/
880
881 static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
882 {
883         SpaceImage *sima = CTX_wm_space_image(C);
884         ARegion *ar = CTX_wm_region(C);
885
886         sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"), NULL);
887         
888         /* ensure pixel exact locations for draw */
889         sima->xof = (int)sima->xof;
890         sima->yof = (int)sima->yof;
891
892         /* XXX notifier? */
893 #if 0
894         if (image_preview_active(curarea, NULL, NULL)) {
895                 /* recalculates new preview rect */
896                 scrarea_do_windraw(curarea);
897                 image_preview_event(2);
898         }
899 #endif
900
901         ED_region_tag_redraw(ar);
902         
903         return OPERATOR_FINISHED;
904 }
905
906 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
907 {
908         /* identifiers */
909         ot->name = "View Zoom Ratio";
910         ot->idname = "IMAGE_OT_view_zoom_ratio";
911         ot->description = "Set zoom ratio of the view";
912         
913         /* api callbacks */
914         ot->exec = image_view_zoom_ratio_exec;
915         ot->poll = space_image_main_area_poll;
916
917         /* flags */
918         ot->flag = OPTYPE_LOCK_BYPASS;
919
920         /* properties */
921         RNA_def_float(ot->srna, "ratio", 0.0f, -FLT_MAX, FLT_MAX,
922                       "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX);
923 }
924
925 /**************** load/replace/save callbacks ******************/
926 static void image_filesel(bContext *C, wmOperator *op, const char *path)
927 {
928         RNA_string_set(op->ptr, "filepath", path);
929         WM_event_add_fileselect(C, op); 
930 }
931
932 /******************** open image operator ********************/
933
934 typedef struct ImageOpenData {
935         PropertyPointerRNA pprop;
936         ImageUser *iuser;
937 } ImageOpenData;
938
939 typedef struct ImageFrame {
940         struct ImageFrame *next, *prev;
941         int framenr;
942 } ImageFrame;
943
944 static void image_open_init(bContext *C, wmOperator *op)
945 {
946         ImageOpenData *iod;
947
948         op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
949         iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
950         uiIDContextProperty(C, &iod->pprop.ptr, &iod->pprop.prop);
951 }
952
953 static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
954 {
955         MEM_freeN(op->customdata);
956         op->customdata = NULL;
957 }
958
959 /**
960  * \brief Get a list of frames from the list of image files matching the first file name sequence pattern
961  * \param ptr [in] the RNA pointer containing the "directory" entry and "files" collection
962  * \param frames [out] the list of frame numbers found in the files matching the first one by name
963  * \param path [out] the full path of the first file in the list of image files
964  */
965 static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen)
966 {
967         char dir[FILE_MAXDIR];
968         bool is_first_entry = true;
969
970         RNA_string_get(ptr, "directory", dir);
971         RNA_BEGIN (ptr, itemptr, "files")
972         {
973                 char base_head[FILE_MAX], base_tail[FILE_MAX];
974                 char head[FILE_MAX], tail[FILE_MAX];
975                 unsigned short digits;
976                 char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
977                 ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
978
979                 /* use the first file in the list as base filename */
980                 if (is_first_entry) {
981                         BLI_join_dirfile(path, maxlen, dir, filename);
982                         frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits);
983                         BLI_addtail(frames, frame);
984                         is_first_entry = false;
985                 }
986                 else {
987                         frame->framenr = BLI_stringdec(filename, head, tail, &digits);
988
989                         /* still in the same sequence */
990                         if ((STREQLEN(base_head, head, FILE_MAX)) &&
991                             (STREQLEN(base_tail, tail, FILE_MAX)))
992                         {
993                                 BLI_addtail(frames, frame);
994                         }
995                         else {
996                                 /* different file base name found, is ignored */
997                                 MEM_freeN(frame);
998                                 break;
999                         }
1000                 }
1001
1002                 MEM_freeN(filename);
1003         }
1004         RNA_END
1005 }
1006
1007 static int image_cmp_frame(const void *a, const void *b)
1008 {
1009         const ImageFrame *frame_a = a;
1010         const ImageFrame *frame_b = b;
1011
1012         if (frame_a->framenr < frame_b->framenr) return -1;
1013         if (frame_a->framenr > frame_b->framenr) return 1;
1014         return 0;
1015 }
1016
1017 /**
1018  * \brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames
1019  * \param frames [in] the list of frame numbers, as a side-effect the list is sorted
1020  * \param ofs [out] offest, the first frame number in the sequence
1021  * \return the number of contiguous frames in the sequence
1022  */
1023 static int image_sequence_get_len(ListBase *frames, int *ofs)
1024 {
1025         ImageFrame *frame;
1026
1027         BLI_sortlist(frames, image_cmp_frame);
1028
1029         frame = frames->first;
1030         if (frame) {
1031                 int frame_curr = frame->framenr;
1032                 (*ofs) = frame_curr;
1033                 while (frame && (frame->framenr == frame_curr)) {
1034                         frame_curr++;
1035                         frame = frame->next;
1036                 }
1037                 return frame_curr - (*ofs);
1038         }
1039         return 0;
1040 }
1041
1042 static int image_open_exec(bContext *C, wmOperator *op)
1043 {
1044         Main *bmain = CTX_data_main(C);
1045         SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1046         Scene *scene = CTX_data_scene(C);
1047         Object *obedit = CTX_data_edit_object(C);
1048         ImageUser *iuser = NULL;
1049         ImageOpenData *iod;
1050         PointerRNA idptr;
1051         Image *ima = NULL;
1052         char path[FILE_MAX];
1053         int frame_seq_len = 0;
1054         int frame_ofs = 1;
1055
1056         const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
1057
1058         RNA_string_get(op->ptr, "filepath", path);
1059
1060         if (!IMB_isanim(path) && RNA_struct_property_is_set(op->ptr, "files") &&
1061             RNA_struct_property_is_set(op->ptr, "directory"))
1062         {
1063                 ListBase frames;
1064
1065                 BLI_listbase_clear(&frames);
1066                 image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
1067                 frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
1068                 BLI_freelistN(&frames);
1069         }
1070
1071         errno = 0;
1072
1073         ima = BKE_image_load_exists(path);
1074
1075         if (!ima) {
1076                 if (op->customdata) MEM_freeN(op->customdata);
1077                 BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
1078                             path, errno ? strerror(errno) : TIP_("unsupported image format"));
1079                 return OPERATOR_CANCELLED;
1080         }
1081
1082         if (!op->customdata)
1083                 image_open_init(C, op);
1084
1085         /* only image path after save, never ibuf */
1086         if (is_relative_path) {
1087                 const char *relbase = ID_BLEND_PATH(bmain, &ima->id);
1088                 BLI_path_rel(ima->name, relbase);
1089         }
1090
1091         /* hook into UI */
1092         iod = op->customdata;
1093
1094         if (iod->pprop.prop) {
1095                 /* when creating new ID blocks, use is already 1, but RNA
1096                  * pointer se also increases user, so this compensates it */
1097                 ima->id.us--;
1098                 if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) {
1099                         ima->source = IMA_SRC_SEQUENCE;
1100                 }
1101                 RNA_id_pointer_create(&ima->id, &idptr);
1102                 RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr);
1103                 RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1104         }
1105
1106         if (iod->iuser) {
1107                 iuser = iod->iuser;
1108         }
1109         else if (sima) {
1110                 ED_space_image_set(sima, scene, obedit, ima);
1111                 iuser = &sima->iuser;
1112         }
1113         else {
1114                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1115                 if (tex && tex->type == TEX_IMAGE) {
1116                         iuser = &tex->iuser;
1117                 }
1118         }
1119
1120         /* initialize because of new image */
1121         if (iuser) {
1122                 iuser->frames = frame_seq_len;
1123                 iuser->sfra = 1;
1124                 iuser->framenr = 1;
1125                 iuser->offset = frame_ofs - 1;
1126                 iuser->fie_ima = 2;
1127         }
1128
1129         /* XXX unpackImage frees image buffers */
1130         ED_preview_kill_jobs(C);
1131         
1132         BKE_image_signal(ima, iuser, IMA_SIGNAL_RELOAD);
1133         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1134         
1135         MEM_freeN(op->customdata);
1136
1137         return OPERATOR_FINISHED;
1138 }
1139
1140 static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1141 {
1142         SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1143         const char *path = U.textudir;
1144         Image *ima = NULL;
1145
1146         if (sima) {
1147                 ima = sima->image;
1148         }
1149
1150         if (ima == NULL) {
1151                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1152                 if (tex && tex->type == TEX_IMAGE)
1153                         ima = tex->ima;
1154         }
1155
1156         if (ima == NULL) {
1157                 PointerRNA ptr;
1158                 PropertyRNA *prop;
1159
1160                 /* hook into UI */
1161                 uiIDContextProperty(C, &ptr, &prop);
1162
1163                 if (prop) {
1164                         PointerRNA oldptr;
1165                         Image *oldima;
1166
1167                         oldptr = RNA_property_pointer_get(&ptr, prop);
1168                         oldima = (Image *)oldptr.id.data;
1169                         /* unlikely to fail but better avoid strange crash */
1170                         if (oldima && GS(oldima->id.name) == ID_IM) {
1171                                 ima = oldima;
1172                         }
1173                 }
1174         }
1175
1176         if (ima)
1177                 path = ima->name;
1178
1179         if (RNA_struct_property_is_set(op->ptr, "filepath"))
1180                 return image_open_exec(C, op);
1181         
1182         image_open_init(C, op);
1183
1184         image_filesel(C, op, path);
1185
1186         return OPERATOR_RUNNING_MODAL;
1187 }
1188
1189 /* called by other space types too */
1190 void IMAGE_OT_open(wmOperatorType *ot)
1191 {
1192         /* identifiers */
1193         ot->name = "Open Image";
1194         ot->description = "Open image";
1195         ot->idname = "IMAGE_OT_open";
1196         
1197         /* api callbacks */
1198         ot->exec = image_open_exec;
1199         ot->invoke = image_open_invoke;
1200         ot->cancel = image_open_cancel;
1201
1202         /* flags */
1203         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1204
1205         /* properties */
1206         WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
1207                                        WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
1208 }
1209
1210 /******************** Match movie length operator ********************/
1211 static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
1212 {
1213         Scene *scene = CTX_data_scene(C);
1214         Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data;
1215         ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data;
1216
1217         if (!ima || !iuser) {
1218                 /* Try to get a Texture, or a SpaceImage from context... */
1219                 SpaceImage *sima = CTX_wm_space_image(C);
1220                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1221                 if (tex && tex->type == TEX_IMAGE) {
1222                         ima = tex->ima;
1223                         iuser = &tex->iuser;
1224                 }
1225                 else if (sima) {
1226                         ima = sima->image;
1227                         iuser = &sima->iuser;
1228                 }
1229                 
1230         }
1231
1232         if (!ima || !iuser || !ima->anim)
1233                 return OPERATOR_CANCELLED;
1234
1235         iuser->frames = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
1236         BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
1237
1238         return OPERATOR_FINISHED;
1239 }
1240
1241 /* called by other space types too */
1242 void IMAGE_OT_match_movie_length(wmOperatorType *ot)
1243 {
1244         /* identifiers */
1245         ot->name = "Match Movie Length";
1246         ot->description = "Set image's user's length to the one of this video";
1247         ot->idname = "IMAGE_OT_match_movie_length";
1248         
1249         /* api callbacks */
1250         ot->exec = image_match_len_exec;
1251
1252         /* flags */
1253         ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL/* | OPTYPE_UNDO */; /* Don't think we need undo for that. */
1254 }
1255
1256 /******************** replace image operator ********************/
1257
1258 static int image_replace_exec(bContext *C, wmOperator *op)
1259 {
1260         SpaceImage *sima = CTX_wm_space_image(C);
1261         char str[FILE_MAX];
1262
1263         if (!sima->image)
1264                 return OPERATOR_CANCELLED;
1265         
1266         RNA_string_get(op->ptr, "filepath", str);
1267
1268         /* we cant do much if the str is longer then FILE_MAX :/ */
1269         BLI_strncpy(sima->image->name, str, sizeof(sima->image->name));
1270
1271         if (sima->image->source == IMA_SRC_GENERATED) {
1272                 sima->image->source = IMA_SRC_FILE;
1273                 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1274         }
1275         
1276         if (BLI_testextensie_array(str, imb_ext_movie))
1277                 sima->image->source = IMA_SRC_MOVIE;
1278         else
1279                 sima->image->source = IMA_SRC_FILE;
1280
1281         /* XXX unpackImage frees image buffers */
1282         ED_preview_kill_jobs(C);
1283         
1284         BKE_icon_changed(BKE_icon_getid(&sima->image->id));
1285         BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1286         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1287
1288         return OPERATOR_FINISHED;
1289 }
1290
1291 static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1292 {
1293         SpaceImage *sima = CTX_wm_space_image(C);
1294
1295         if (!sima->image)
1296                 return OPERATOR_CANCELLED;
1297
1298         if (RNA_struct_property_is_set(op->ptr, "filepath"))
1299                 return image_replace_exec(C, op);
1300
1301         if (!RNA_struct_property_is_set(op->ptr, "relative_path"))
1302                 RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->name));
1303
1304         image_filesel(C, op, sima->image->name);
1305
1306         return OPERATOR_RUNNING_MODAL;
1307 }
1308
1309 void IMAGE_OT_replace(wmOperatorType *ot)
1310 {
1311         /* identifiers */
1312         ot->name = "Replace Image";
1313         ot->idname = "IMAGE_OT_replace";
1314         ot->description = "Replace current image by another one from disk";
1315         
1316         /* api callbacks */
1317         ot->exec = image_replace_exec;
1318         ot->invoke = image_replace_invoke;
1319         ot->poll = space_image_poll;
1320
1321         /* flags */
1322         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1323
1324         /* properties */
1325         WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
1326                                        WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
1327 }
1328
1329 /******************** save image as operator ********************/
1330
1331 typedef struct {
1332         /* matching scene->r settings */
1333         //short planes, imtype, subimtype, quality;
1334         ImageFormatData im_format;
1335         char filepath[FILE_MAX]; /* keep absolute */
1336 } SaveImageOptions;
1337
1338 static void save_image_options_defaults(SaveImageOptions *simopts)
1339 {
1340         BKE_imformat_defaults(&simopts->im_format);
1341         simopts->filepath[0] = '\0';
1342 }
1343
1344 static char imtype_best_depth(ImBuf *ibuf, const char imtype)
1345 {
1346         const char depth_ok = BKE_imtype_valid_depths(imtype);
1347
1348         if (ibuf->rect_float) {
1349                 if (depth_ok & R_IMF_CHAN_DEPTH_32) return R_IMF_CHAN_DEPTH_32;
1350                 if (depth_ok & R_IMF_CHAN_DEPTH_24) return R_IMF_CHAN_DEPTH_24;
1351                 if (depth_ok & R_IMF_CHAN_DEPTH_16) return R_IMF_CHAN_DEPTH_16;
1352                 if (depth_ok & R_IMF_CHAN_DEPTH_12) return R_IMF_CHAN_DEPTH_12;
1353                 return R_IMF_CHAN_DEPTH_8;
1354         }
1355         else {
1356                 if (depth_ok & R_IMF_CHAN_DEPTH_8) return R_IMF_CHAN_DEPTH_8;
1357                 if (depth_ok & R_IMF_CHAN_DEPTH_12) return R_IMF_CHAN_DEPTH_12;
1358                 if (depth_ok & R_IMF_CHAN_DEPTH_16) return R_IMF_CHAN_DEPTH_16;
1359                 if (depth_ok & R_IMF_CHAN_DEPTH_24) return R_IMF_CHAN_DEPTH_24;
1360                 if (depth_ok & R_IMF_CHAN_DEPTH_32) return R_IMF_CHAN_DEPTH_32;
1361                 return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
1362         }
1363 }
1364
1365 static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, Scene *scene,
1366                                    const bool guess_path, const bool save_as_render)
1367 {
1368         void *lock;
1369         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
1370
1371         if (ibuf) {
1372                 Image *ima = sima->image;
1373                 bool is_depth_set = false;
1374
1375                 if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
1376                         /* imtype */
1377                         simopts->im_format = scene->r.im_format;
1378                         is_depth_set = true;
1379                 }
1380                 else {
1381                         if (ima->source == IMA_SRC_GENERATED) {
1382                                 simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
1383                         }
1384                         else {
1385                                 BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
1386                                 simopts->im_format.quality = ibuf->ftype & 0xff;
1387                         }
1388                         simopts->im_format.quality = ibuf->ftype & 0xff;
1389                 }
1390
1391                 simopts->im_format.planes = ibuf->planes;
1392
1393                 //simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */
1394
1395                 BLI_strncpy(simopts->filepath, ibuf->name, sizeof(simopts->filepath));
1396
1397                 /* sanitize all settings */
1398
1399                 /* unlikely but just in case */
1400                 if (ELEM(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
1401                         simopts->im_format.planes = R_IMF_PLANES_RGBA;
1402                 }
1403
1404                 /* depth, account for float buffer and format support */
1405                 if (is_depth_set == false) {
1406                         simopts->im_format.depth = imtype_best_depth(ibuf, simopts->im_format.imtype);
1407                 }
1408
1409                 /* some formats don't use quality so fallback to scenes quality */
1410                 if (simopts->im_format.quality == 0) {
1411                         simopts->im_format.quality = scene->r.im_format.quality;
1412                 }
1413
1414                 /* check for empty path */
1415                 if (guess_path && simopts->filepath[0] == 0) {
1416                         const bool is_prev_save = !STREQ(G.ima, "//");
1417                         if (save_as_render) {
1418                                 if (is_prev_save) {
1419                                         BLI_strncpy(simopts->filepath, G.ima, sizeof(simopts->filepath));
1420                                 }
1421                                 else {
1422                                         BLI_strncpy(simopts->filepath, "//untitled", sizeof(simopts->filepath));
1423                                         BLI_path_abs(simopts->filepath, G.main->name);
1424                                 }
1425                         }
1426                         else {
1427                                 BLI_snprintf(simopts->filepath, sizeof(simopts->filepath), "//%s", ima->id.name + 2);
1428                                 BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : G.main->name);
1429                         }
1430                 }
1431
1432                 /* color management */
1433                 BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
1434                 BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
1435         }
1436
1437         ED_space_image_release_buffer(sima, ibuf, lock);
1438
1439         return (ibuf != NULL);
1440 }
1441
1442 static void save_image_options_from_op(SaveImageOptions *simopts, wmOperator *op)
1443 {
1444         if (op->customdata) {
1445                 BKE_color_managed_view_settings_free(&simopts->im_format.view_settings);
1446
1447                 simopts->im_format = *(ImageFormatData *)op->customdata;
1448         }
1449
1450         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1451                 RNA_string_get(op->ptr, "filepath", simopts->filepath);
1452                 BLI_path_abs(simopts->filepath, G.main->name);
1453         }
1454 }
1455
1456 static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
1457 {
1458         if (op->customdata) {
1459                 BKE_color_managed_view_settings_free(&((ImageFormatData *)op->customdata)->view_settings);
1460
1461                 *(ImageFormatData *)op->customdata = simopts->im_format;
1462         }
1463
1464         RNA_string_set(op->ptr, "filepath", simopts->filepath);
1465 }
1466
1467 /**
1468  * \return success.
1469  * \note ``ima->name`` and ``ibuf->name`` should end up the same.
1470  */
1471 static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
1472 {
1473         Image *ima = ED_space_image(sima);
1474         void *lock;
1475         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
1476         bool ok = false;
1477
1478         if (ibuf) {
1479                 ImBuf *colormanaged_ibuf;
1480                 const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
1481                 const bool relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
1482                 const bool save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
1483                 const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
1484                 ImageFormatData *imf = &simopts->im_format;
1485
1486                 /* old global to ensure a 2nd save goes to same dir */
1487                 BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima));
1488
1489                 WM_cursor_wait(1);
1490
1491                 if (ima->type == IMA_TYPE_R_RESULT) {
1492                         /* enforce user setting for RGB or RGBA, but skip BW */
1493                         if (simopts->im_format.planes == R_IMF_PLANES_RGBA) {
1494                                 ibuf->planes = R_IMF_PLANES_RGBA;
1495                         }
1496                         else if (simopts->im_format.planes == R_IMF_PLANES_RGB) {
1497                                 ibuf->planes = R_IMF_PLANES_RGB;
1498                         }
1499                 }
1500                 else {
1501                         /* TODO, better solution, if a 24bit image is painted onto it may contain alpha */
1502                         if ((simopts->im_format.planes == R_IMF_PLANES_RGBA) &&
1503                             /* it has been painted onto */
1504                             (ibuf->userflags & IB_BITMAPDIRTY))
1505                         {
1506                                 /* checks each pixel, not ideal */
1507                                 ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB;
1508                         }
1509                 }
1510
1511                 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
1512
1513                 if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
1514                         Scene *scene = CTX_data_scene(C);
1515                         RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
1516                         if (rr) {
1517                                 ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, simopts->im_format.exr_codec);
1518                         }
1519                         else {
1520                                 BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
1521                         }
1522                         BKE_image_release_renderresult(scene, ima);
1523                 }
1524                 else {
1525                         ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, &simopts->im_format, save_copy);
1526                 }
1527
1528                 if (ok) {
1529                         if (!save_copy) {
1530                                 if (do_newpath) {
1531                                         BLI_strncpy(ibuf->name, simopts->filepath, sizeof(ibuf->name));
1532                                         BLI_strncpy(ima->name, simopts->filepath, sizeof(ima->name));
1533                                 }
1534
1535                                 ibuf->userflags &= ~IB_BITMAPDIRTY;
1536
1537                                 /* change type? */
1538                                 if (ima->type == IMA_TYPE_R_RESULT) {
1539                                         ima->type = IMA_TYPE_IMAGE;
1540
1541                                         /* workaround to ensure the render result buffer is no longer used
1542                                          * by this image, otherwise can crash when a new render result is
1543                                          * created. */
1544                                         if (ibuf->rect && !(ibuf->mall & IB_rect))
1545                                                 imb_freerectImBuf(ibuf);
1546                                         if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
1547                                                 imb_freerectfloatImBuf(ibuf);
1548                                         if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
1549                                                 IMB_freezbufImBuf(ibuf);
1550                                         if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
1551                                                 IMB_freezbuffloatImBuf(ibuf);
1552                                 }
1553                                 if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
1554                                         ima->source = IMA_SRC_FILE;
1555                                         ima->type = IMA_TYPE_IMAGE;
1556                                 }
1557
1558                                 /* only image path, never ibuf */
1559                                 if (relative) {
1560                                         BLI_path_rel(ima->name, relbase); /* only after saving */
1561                                 }
1562
1563                                 IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
1564                         }
1565                 }
1566                 else {
1567                         BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", simopts->filepath);
1568                 }
1569
1570
1571                 WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1572
1573                 WM_cursor_wait(0);
1574
1575                 if (colormanaged_ibuf != ibuf) {
1576                         /* This guys might be modified by image buffer write functions,
1577                          * need to copy them back from color managed image buffer to an
1578                          * original one, so file type of image is being properly updated.
1579                          */
1580                         ibuf->ftype = colormanaged_ibuf->ftype;
1581                         ibuf->planes = colormanaged_ibuf->planes;
1582
1583                         IMB_freeImBuf(colormanaged_ibuf);
1584                 }
1585         }
1586
1587         ED_space_image_release_buffer(sima, ibuf, lock);
1588
1589         return ok;
1590 }
1591
1592 static void image_save_as_free(wmOperator *op)
1593 {
1594         if (op->customdata) {
1595                 ImageFormatData *im_format = (ImageFormatData *)op->customdata;
1596                 BKE_color_managed_view_settings_free(&im_format->view_settings);
1597
1598                 MEM_freeN(op->customdata);
1599                 op->customdata = NULL;
1600         }
1601 }
1602
1603 static int image_save_as_exec(bContext *C, wmOperator *op)
1604 {
1605         SpaceImage *sima = CTX_wm_space_image(C);
1606         SaveImageOptions simopts;
1607
1608         save_image_options_defaults(&simopts);
1609
1610         /* just in case to initialize values,
1611          * these should be set on invoke or by the caller. */
1612         save_image_options_init(&simopts, sima, CTX_data_scene(C), false, false);
1613
1614         save_image_options_from_op(&simopts, op);
1615
1616         save_image_doit(C, sima, op, &simopts, true);
1617
1618         image_save_as_free(op);
1619         return OPERATOR_FINISHED;
1620 }
1621
1622
1623 static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
1624 {
1625         ImageFormatData *imf = op->customdata;
1626         return WM_operator_filesel_ensure_ext_imtype(op, imf);
1627 }
1628
1629 static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1630 {
1631         SpaceImage *sima = CTX_wm_space_image(C);
1632         Image *ima = ED_space_image(sima);
1633         Scene *scene = CTX_data_scene(C);
1634         SaveImageOptions simopts;
1635         const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) || (ima->flag & IMA_VIEW_AS_RENDER));
1636
1637         if (RNA_struct_property_is_set(op->ptr, "filepath"))
1638                 return image_save_as_exec(C, op);
1639
1640         save_image_options_defaults(&simopts);
1641
1642         if (save_image_options_init(&simopts, sima, scene, true, save_as_render) == 0)
1643                 return OPERATOR_CANCELLED;
1644         save_image_options_to_op(&simopts, op);
1645
1646         /* enable save_copy by default for render results */
1647         if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) && !RNA_struct_property_is_set(op->ptr, "copy")) {
1648                 RNA_boolean_set(op->ptr, "copy", true);
1649         }
1650
1651         RNA_boolean_set(op->ptr, "save_as_render", save_as_render);
1652
1653         op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
1654         memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
1655
1656         image_filesel(C, op, simopts.filepath);
1657
1658         return OPERATOR_RUNNING_MODAL;
1659 }
1660
1661 static void image_save_as_cancel(bContext *UNUSED(C), wmOperator *op)
1662 {
1663         image_save_as_free(op);
1664 }
1665
1666 static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
1667 {
1668         const char *prop_id = RNA_property_identifier(prop);
1669
1670         return !(STREQ(prop_id, "filepath") ||
1671                  STREQ(prop_id, "directory") ||
1672                  STREQ(prop_id, "filename") ||
1673                  /* when saving a copy, relative path has no effect */
1674                  ((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy"))
1675                  );
1676 }
1677
1678 static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
1679 {
1680         uiLayout *layout = op->layout;
1681         ImageFormatData *imf = op->customdata;
1682         PointerRNA ptr;
1683
1684         /* image template */
1685         RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &ptr);
1686         uiTemplateImageSettings(layout, &ptr, false);
1687
1688         /* main draw call */
1689         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1690         uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0');
1691 }
1692
1693 static int image_save_as_poll(bContext *C)
1694 {
1695         if (space_image_buffer_exists_poll(C)) {
1696                 if (G.is_rendering) {
1697                         /* no need to NULL check here */
1698                         SpaceImage *sima = CTX_wm_space_image(C);
1699                         Image *ima = ED_space_image(sima);
1700
1701                         if (ima->source == IMA_SRC_VIEWER) {
1702                                 CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
1703                                 return false;
1704                         }
1705                 }
1706                 return true;
1707         }
1708         return false;
1709 }
1710
1711 void IMAGE_OT_save_as(wmOperatorType *ot)
1712 {
1713 //      PropertyRNA *prop;
1714
1715         /* identifiers */
1716         ot->name = "Save As Image";
1717         ot->idname = "IMAGE_OT_save_as";
1718         ot->description = "Save the image with another name and/or settings";
1719         
1720         /* api callbacks */
1721         ot->exec = image_save_as_exec;
1722         ot->check = image_save_as_check;
1723         ot->invoke = image_save_as_invoke;
1724         ot->cancel = image_save_as_cancel;
1725         ot->ui = image_save_as_draw;
1726         ot->poll = image_save_as_poll;
1727
1728         /* flags */
1729         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1730
1731         /* properties */
1732         RNA_def_boolean(ot->srna, "save_as_render", 0, "Save As Render", "Apply render part of display transform when saving byte image");
1733         RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
1734
1735         WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_SAVE,
1736                                        WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
1737 }
1738
1739 /******************** save image operator ********************/
1740
1741 static int image_save_exec(bContext *C, wmOperator *op)
1742 {
1743         SpaceImage *sima = CTX_wm_space_image(C);
1744         Scene *scene = CTX_data_scene(C);
1745         SaveImageOptions simopts;
1746
1747         save_image_options_defaults(&simopts);
1748         if (save_image_options_init(&simopts, sima, scene, false, false) == 0)
1749                 return OPERATOR_CANCELLED;
1750         save_image_options_from_op(&simopts, op);
1751
1752         if (BLI_exists(simopts.filepath) && BLI_file_is_writable(simopts.filepath)) {
1753                 if (save_image_doit(C, sima, op, &simopts, false)) {
1754                         /* report since this can be called from key-shortcuts */
1755                         BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", simopts.filepath);
1756                 }
1757         }
1758         else {
1759                 BKE_reportf(op->reports, RPT_ERROR, "Cannot save image, path '%s' is not writable", simopts.filepath);
1760                 return OPERATOR_CANCELLED;
1761         }
1762
1763         return OPERATOR_FINISHED;
1764 }
1765
1766 void IMAGE_OT_save(wmOperatorType *ot)
1767 {
1768         /* identifiers */
1769         ot->name = "Save Image";
1770         ot->idname = "IMAGE_OT_save";
1771         ot->description = "Save the image with current name and settings";
1772         
1773         /* api callbacks */
1774         ot->exec = image_save_exec;
1775         ot->poll = space_image_file_exists_poll;
1776
1777         /* flags */
1778         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1779 }
1780
1781 /******************* save sequence operator ********************/
1782
1783 static int image_save_sequence_exec(bContext *C, wmOperator *op)
1784 {
1785         Main *bmain = CTX_data_main(C);
1786         SpaceImage *sima = CTX_wm_space_image(C);
1787         ImBuf *ibuf, *first_ibuf = NULL;
1788         int tot = 0;
1789         char di[FILE_MAX];
1790         struct MovieCacheIter *iter;
1791         
1792         if (sima->image == NULL)
1793                 return OPERATOR_CANCELLED;
1794
1795         if (sima->image->source != IMA_SRC_SEQUENCE) {
1796                 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
1797                 return OPERATOR_CANCELLED;
1798         }
1799
1800         if (sima->image->type == IMA_TYPE_MULTILAYER) {
1801                 BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
1802                 return OPERATOR_CANCELLED;
1803         }
1804         
1805         /* get total dirty buffers and first dirty buffer which is used for menu */
1806         ibuf = NULL;
1807         if (sima->image->cache != NULL) {
1808                 iter = IMB_moviecacheIter_new(sima->image->cache);
1809                 while (!IMB_moviecacheIter_done(iter)) {
1810                         ibuf = IMB_moviecacheIter_getImBuf(iter);
1811                         if (ibuf->userflags & IB_BITMAPDIRTY) {
1812                                 if (first_ibuf == NULL) {
1813                                         first_ibuf = ibuf;
1814                                 }
1815                                 tot++;
1816                         }
1817                         IMB_moviecacheIter_step(iter);
1818                 }
1819                 IMB_moviecacheIter_free(iter);
1820         }
1821         
1822         if (tot == 0) {
1823                 BKE_report(op->reports, RPT_WARNING, "No images have been changed");
1824                 return OPERATOR_CANCELLED;
1825         }
1826
1827         /* get a filename for menu */
1828         BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
1829         BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
1830
1831         iter = IMB_moviecacheIter_new(sima->image->cache);
1832         while (!IMB_moviecacheIter_done(iter)) {
1833                 ibuf = IMB_moviecacheIter_getImBuf(iter);
1834
1835                 if (ibuf->userflags & IB_BITMAPDIRTY) {
1836                         char name[FILE_MAX];
1837                         BLI_strncpy(name, ibuf->name, sizeof(name));
1838
1839                         BLI_path_abs(name, bmain->name);
1840
1841                         if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
1842                                 BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", name);
1843                                 break;
1844                         }
1845
1846                         BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->name);
1847                         ibuf->userflags &= ~IB_BITMAPDIRTY;
1848                 }
1849
1850                 IMB_moviecacheIter_step(iter);
1851         }
1852         IMB_moviecacheIter_free(iter);
1853
1854         return OPERATOR_FINISHED;
1855 }
1856
1857 void IMAGE_OT_save_sequence(wmOperatorType *ot)
1858 {
1859         /* identifiers */
1860         ot->name = "Save Sequence";
1861         ot->idname = "IMAGE_OT_save_sequence";
1862         ot->description = "Save a sequence of images";
1863         
1864         /* api callbacks */
1865         ot->exec = image_save_sequence_exec;
1866         ot->poll = space_image_buffer_exists_poll;
1867
1868         /* flags */
1869         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1870 }
1871
1872 /******************** reload image operator ********************/
1873
1874 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
1875 {
1876         Image *ima = CTX_data_edit_image(C);
1877         SpaceImage *sima = CTX_wm_space_image(C);
1878
1879         if (!ima)
1880                 return OPERATOR_CANCELLED;
1881
1882         /* XXX unpackImage frees image buffers */
1883         ED_preview_kill_jobs(C);
1884         
1885         // XXX other users?
1886         BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
1887         DAG_id_tag_update(&ima->id, 0);
1888
1889         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1890         
1891         return OPERATOR_FINISHED;
1892 }
1893
1894 void IMAGE_OT_reload(wmOperatorType *ot)
1895 {
1896         /* identifiers */
1897         ot->name = "Reload Image";
1898         ot->idname = "IMAGE_OT_reload";
1899         ot->description = "Reload current image from disk";
1900         
1901         /* api callbacks */
1902         ot->exec = image_reload_exec;
1903
1904         /* flags */
1905         ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
1906 }
1907
1908 /********************** new image operator *********************/
1909 #define IMA_DEF_NAME N_("Untitled")
1910
1911 enum {
1912         GEN_CONTEXT_NONE = 0,
1913         GEN_CONTEXT_PAINT_CANVAS = 1,
1914         GEN_CONTEXT_PAINT_STENCIL = 2
1915 };
1916
1917 static int image_new_exec(bContext *C, wmOperator *op)
1918 {
1919         SpaceImage *sima;
1920         Scene *scene;
1921         Object *obedit;
1922         Image *ima;
1923         Main *bmain;
1924         PointerRNA ptr, idptr;
1925         PropertyRNA *prop;
1926         char _name[MAX_ID_NAME - 2];
1927         char *name = _name;
1928         float color[4];
1929         int width, height, floatbuf, gen_type, alpha;
1930         int gen_context;
1931
1932         /* retrieve state */
1933         sima = CTX_wm_space_image(C);
1934         scene = CTX_data_scene(C);
1935         obedit = CTX_data_edit_object(C);
1936         bmain = CTX_data_main(C);
1937
1938         prop = RNA_struct_find_property(op->ptr, "name");
1939         RNA_property_string_get(op->ptr, prop, name);
1940         if (!RNA_property_is_set(op->ptr, prop)) {
1941                 /* Default value, we can translate! */
1942                 name = (char *)DATA_(name);
1943         }
1944         width = RNA_int_get(op->ptr, "width");
1945         height = RNA_int_get(op->ptr, "height");
1946         floatbuf = RNA_boolean_get(op->ptr, "float");
1947         gen_type = RNA_enum_get(op->ptr, "generated_type");
1948         RNA_float_get_array(op->ptr, "color", color);
1949         alpha = RNA_boolean_get(op->ptr, "alpha");
1950         gen_context = RNA_enum_get(op->ptr, "gen_context");
1951
1952         if (!alpha)
1953                 color[3] = 1.0f;
1954
1955         ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color);
1956
1957         if (!ima)
1958                 return OPERATOR_CANCELLED;
1959
1960         /* hook into UI */
1961         uiIDContextProperty(C, &ptr, &prop);
1962
1963         if (prop) {
1964                 /* when creating new ID blocks, use is already 1, but RNA
1965                  * pointer se also increases user, so this compensates it */
1966                 ima->id.us--;
1967
1968                 RNA_id_pointer_create(&ima->id, &idptr);
1969                 RNA_property_pointer_set(&ptr, prop, idptr);
1970                 RNA_property_update(C, &ptr, prop);
1971         }
1972         else if (sima) {
1973                 ED_space_image_set(sima, scene, obedit, ima);
1974         }
1975         else if (gen_context == GEN_CONTEXT_PAINT_CANVAS) {
1976                 bScreen *sc;
1977                 Object *ob = CTX_data_active_object(C);
1978                 
1979                 GPU_drawobject_free(ob->derivedFinal);  
1980                 if (scene->toolsettings->imapaint.canvas)
1981                         id_us_min(&scene->toolsettings->imapaint.canvas->id);
1982                 scene->toolsettings->imapaint.canvas = ima;
1983                 
1984                 for (sc = bmain->screen.first; sc; sc = sc->id.next) {
1985                         ScrArea *sa;
1986                         for (sa = sc->areabase.first; sa; sa = sa->next) {
1987                                 SpaceLink *sl;
1988                                 for (sl = sa->spacedata.first; sl; sl = sl->next) {
1989                                         if (sl->spacetype == SPACE_IMAGE) {
1990                                                 SpaceImage *sima = (SpaceImage *)sl;
1991                                                 
1992                                                 if (!sima->pin)
1993                                                         ED_space_image_set(sima, scene, scene->obedit, ima);
1994                                         }
1995                                 }
1996                         }
1997                 }
1998                 BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
1999                 WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
2000         }
2001         else if (gen_context == GEN_CONTEXT_PAINT_STENCIL) {
2002                 Object *ob = CTX_data_active_object(C);
2003                 if (scene->toolsettings->imapaint.stencil)
2004                         id_us_min(&scene->toolsettings->imapaint.stencil->id);
2005                 scene->toolsettings->imapaint.stencil = ima;
2006                 BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);      
2007                 WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);             
2008         }
2009         else {
2010                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
2011                 if (tex && tex->type == TEX_IMAGE) {
2012                         if (tex->ima)
2013                                 id_us_min(&tex->ima->id);
2014                         tex->ima = ima;
2015                         ED_area_tag_redraw(CTX_wm_area(C));
2016                 }
2017         }
2018
2019         BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
2020         
2021         WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
2022         
2023         return OPERATOR_FINISHED;
2024 }
2025
2026 /* XXX, Ton is not a fan of OK buttons but using this function to avoid undo/redo bug while in mesh-editmode, - campbell */
2027 /* XXX Note: the WM_operator_props_dialog_popup() doesn't work for uiIDContextProperty(), image is not being that way */
2028 static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2029 {
2030         /* Better for user feedback. */
2031         RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2032         return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
2033 }
2034
2035 void IMAGE_OT_new(wmOperatorType *ot)
2036 {
2037         PropertyRNA *prop;
2038         static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2039
2040         static EnumPropertyItem gen_context_items[] = {
2041                 {GEN_CONTEXT_NONE, "NONE", 0, "None", ""},
2042                 {GEN_CONTEXT_PAINT_CANVAS, "PAINT_CANVAS", 0, "Paint Canvas", ""},
2043             {GEN_CONTEXT_PAINT_STENCIL, "PAINT_STENCIL", 0, "Paint Stencil", ""},
2044                 {0, NULL, 0, NULL, NULL}
2045         };
2046         
2047         /* identifiers */
2048         ot->name = "New Image";
2049         ot->description = "Create a new image";
2050         ot->idname = "IMAGE_OT_new";
2051         
2052         /* api callbacks */
2053         ot->exec = image_new_exec;
2054         ot->invoke = image_new_invoke;
2055         
2056         /* flags */
2057         ot->flag = OPTYPE_UNDO;
2058
2059         /* properties */
2060         RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
2061         prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2062         RNA_def_property_subtype(prop, PROP_PIXEL);
2063         prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2064         RNA_def_property_subtype(prop, PROP_PIXEL);
2065         prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2066         RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
2067         RNA_def_property_float_array_default(prop, default_color);
2068         RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
2069         RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
2070                      "Generated Type", "Fill the image with a grid for UV map testing");
2071         RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
2072         prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
2073         RNA_def_property_flag(prop, PROP_HIDDEN);
2074
2075 }
2076
2077 #undef IMA_DEF_NAME
2078
2079 /********************* invert operators *********************/
2080
2081 static int image_invert_poll(bContext *C)
2082 {
2083         Image *ima = CTX_data_edit_image(C);
2084
2085         return BKE_image_has_ibuf(ima, NULL);
2086 }
2087
2088 static int image_invert_exec(bContext *C, wmOperator *op)
2089 {
2090         Image *ima = CTX_data_edit_image(C);
2091         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2092         SpaceImage *sima = CTX_wm_space_image(C);
2093         /* undo is supported only on image paint mode currently */
2094         bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2095
2096         /* flags indicate if this channel should be inverted */
2097         const bool r = RNA_boolean_get(op->ptr, "invert_r");
2098         const bool g = RNA_boolean_get(op->ptr, "invert_g");
2099         const bool b = RNA_boolean_get(op->ptr, "invert_b");
2100         const bool a = RNA_boolean_get(op->ptr, "invert_a");
2101
2102         int i;
2103
2104         if (ibuf == NULL)  /* TODO: this should actually never happen, but does for render-results -> cleanup */
2105                 return OPERATOR_CANCELLED;
2106
2107         if (support_undo) {
2108                 ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
2109                                          ED_image_undo_restore, ED_image_undo_free, NULL);
2110                 /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
2111                  * but better do this right in case someone copies this for a tool that uses partial redraw better */
2112                 ED_imapaint_clear_partial_redraw();
2113                 ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
2114         }
2115         /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
2116         if (ibuf->rect_float) {
2117                 
2118                 float *fp = (float *) ibuf->rect_float;
2119                 for (i = ibuf->x * ibuf->y; i > 0; i--, fp += 4) {
2120                         if (r) fp[0] = 1.0f - fp[0];
2121                         if (g) fp[1] = 1.0f - fp[1];
2122                         if (b) fp[2] = 1.0f - fp[2];
2123                         if (a) fp[3] = 1.0f - fp[3];
2124                 }
2125
2126                 if (ibuf->rect) {
2127                         IMB_rect_from_float(ibuf);
2128                 }
2129         }
2130         else if (ibuf->rect) {
2131                 
2132                 char *cp = (char *) ibuf->rect;
2133                 for (i = ibuf->x * ibuf->y; i > 0; i--, cp += 4) {
2134                         if (r) cp[0] = 255 - cp[0];
2135                         if (g) cp[1] = 255 - cp[1];
2136                         if (b) cp[2] = 255 - cp[2];
2137                         if (a) cp[3] = 255 - cp[3];
2138                 }
2139         }
2140         else {
2141                 BKE_image_release_ibuf(ima, ibuf, NULL);
2142                 return OPERATOR_CANCELLED;
2143         }
2144
2145         ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;
2146
2147         if (ibuf->mipmap[0])
2148                 ibuf->userflags |= IB_MIPMAP_INVALID;
2149
2150         if (support_undo)
2151                 ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
2152
2153         /* force GPU reupload, all image is invalid */
2154         GPU_free_image(ima);
2155
2156         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2157
2158         BKE_image_release_ibuf(ima, ibuf, NULL);
2159
2160         return OPERATOR_FINISHED;
2161 }
2162
2163 void IMAGE_OT_invert(wmOperatorType *ot)
2164 {
2165         PropertyRNA *prop;
2166
2167         /* identifiers */
2168         ot->name = "Invert Channels";
2169         ot->idname = "IMAGE_OT_invert";
2170         ot->description = "Invert image's channels";
2171         
2172         /* api callbacks */
2173         ot->exec = image_invert_exec;
2174         ot->poll = image_invert_poll;
2175         
2176         /* properties */
2177         prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
2178         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2179         prop = RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel");
2180         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2181         prop = RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel");
2182         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2183         prop = RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel");
2184         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2185         
2186         /* flags */
2187         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2188 }
2189
2190 /********************* pack operator *********************/
2191
2192 static bool image_pack_test(bContext *C, wmOperator *op)
2193 {
2194         Image *ima = CTX_data_edit_image(C);
2195         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2196
2197         if (!ima)
2198                 return 0;
2199         if (!as_png && ima->packedfile)
2200                 return 0;
2201
2202         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2203                 BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
2204                 return 0;
2205         }
2206
2207         return 1;
2208 }
2209
2210 static int image_pack_exec(bContext *C, wmOperator *op)
2211 {
2212         struct Main *bmain = CTX_data_main(C);
2213         Image *ima = CTX_data_edit_image(C);
2214         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2215         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2216
2217         if (!image_pack_test(C, op))
2218                 return OPERATOR_CANCELLED;
2219         
2220         if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
2221                 BKE_report(op->reports, RPT_ERROR, "Cannot pack edited image from disk, only as internal PNG");
2222                 return OPERATOR_CANCELLED;
2223         }
2224
2225         if (as_png)
2226                 BKE_image_memorypack(ima);
2227         else
2228                 ima->packedfile = newPackedFile(op->reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
2229
2230         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2231
2232         BKE_image_release_ibuf(ima, ibuf, NULL);
2233
2234         return OPERATOR_FINISHED;
2235 }
2236
2237 static int image_pack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2238 {
2239         Image *ima = CTX_data_edit_image(C);
2240         ImBuf *ibuf;
2241         uiPopupMenu *pup;
2242         uiLayout *layout;
2243         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2244
2245         if (!image_pack_test(C, op))
2246                 return OPERATOR_CANCELLED;
2247
2248         ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2249
2250         if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
2251                 pup = uiPupMenuBegin(C, IFACE_("OK"), ICON_QUESTION);
2252                 layout = uiPupMenuLayout(pup);
2253                 uiItemBooleanO(layout, IFACE_("Can't pack edited image from disk, pack as internal PNG?"), ICON_NONE,
2254                                op->idname, "as_png", 1);
2255                 uiPupMenuEnd(C, pup);
2256
2257                 BKE_image_release_ibuf(ima, ibuf, NULL);
2258
2259                 return OPERATOR_CANCELLED;
2260         }
2261
2262         BKE_image_release_ibuf(ima, ibuf, NULL);
2263
2264         return image_pack_exec(C, op);
2265 }
2266
2267 void IMAGE_OT_pack(wmOperatorType *ot)
2268 {
2269         /* identifiers */
2270         ot->name = "Pack Image";
2271         ot->description = "Pack an image as embedded data into the .blend file"; 
2272         ot->idname = "IMAGE_OT_pack";
2273         
2274         /* api callbacks */
2275         ot->exec = image_pack_exec;
2276         ot->invoke = image_pack_invoke;
2277
2278         /* flags */
2279         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2280
2281         /* properties */
2282         RNA_def_boolean(ot->srna, "as_png", 0, "Pack As PNG", "Pack image as lossless PNG");
2283 }
2284
2285 /********************* unpack operator *********************/
2286
2287 static int image_unpack_exec(bContext *C, wmOperator *op)
2288 {
2289         Image *ima = CTX_data_edit_image(C);
2290         int method = RNA_enum_get(op->ptr, "method");
2291
2292         /* find the suppplied image by name */
2293         if (RNA_struct_property_is_set(op->ptr, "id")) {
2294                 char imaname[MAX_ID_NAME - 2];
2295                 RNA_string_get(op->ptr, "id", imaname);
2296                 ima = BLI_findstring(&CTX_data_main(C)->image, imaname, offsetof(ID, name) + 2);
2297                 if (!ima) ima = CTX_data_edit_image(C);
2298         }
2299         
2300         if (!ima || !ima->packedfile)
2301                 return OPERATOR_CANCELLED;
2302
2303         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2304                 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2305                 return OPERATOR_CANCELLED;
2306         }
2307
2308         if (G.fileflags & G_AUTOPACK)
2309                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
2310         
2311         /* XXX unpackImage frees image buffers */
2312         ED_preview_kill_jobs(C);
2313         
2314         unpackImage(op->reports, ima, method);
2315         
2316         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2317
2318         return OPERATOR_FINISHED;
2319 }
2320
2321 static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2322 {
2323         Image *ima = CTX_data_edit_image(C);
2324
2325         if (RNA_struct_property_is_set(op->ptr, "id"))
2326                 return image_unpack_exec(C, op);
2327                 
2328         if (!ima || !ima->packedfile)
2329                 return OPERATOR_CANCELLED;
2330
2331         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2332                 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2333                 return OPERATOR_CANCELLED;
2334         }
2335
2336         if (G.fileflags & G_AUTOPACK)
2337                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
2338
2339         unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", ima->packedfile);
2340
2341         return OPERATOR_FINISHED;
2342 }
2343
2344 void IMAGE_OT_unpack(wmOperatorType *ot)
2345 {
2346         /* identifiers */
2347         ot->name = "Unpack Image";
2348         ot->description = "Save an image packed in the .blend file to disk"; 
2349         ot->idname = "IMAGE_OT_unpack";
2350         
2351         /* api callbacks */
2352         ot->exec = image_unpack_exec;
2353         ot->invoke = image_unpack_invoke;
2354
2355         /* flags */
2356         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2357         
2358         /* properties */
2359         RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
2360         RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
2361 }
2362
2363 /******************** sample image operator ********************/
2364
2365 typedef struct ImageSampleInfo {
2366         ARegionType *art;
2367         void *draw_handle;
2368         int x, y;
2369         int channels;
2370
2371         unsigned char col[4];
2372         float colf[4];
2373         float linearcol[4];
2374         int z;
2375         float zf;
2376
2377         unsigned char *colp;
2378         const float *colfp;
2379         int *zp;
2380         float *zfp;
2381
2382         int draw;
2383         int color_manage;
2384         int use_default_view;
2385 } ImageSampleInfo;
2386
2387 static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
2388 {
2389         ImageSampleInfo *info = arg_info;
2390         if (info->draw) {
2391                 Scene *scene = CTX_data_scene(C);
2392
2393                 ED_image_draw_info(scene, ar, info->color_manage, info->use_default_view, info->channels,
2394                                    info->x, info->y, info->colp, info->colfp, info->linearcol, info->zp, info->zfp);
2395         }
2396 }
2397
2398 /* Returns color in the display space, matching ED_space_node_color_sample(). */
2399 bool ED_space_image_color_sample(Scene *scene, SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
2400 {
2401         const char *display_device = scene->display_settings.display_device;
2402         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
2403         void *lock;
2404         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2405         float fx, fy;
2406         bool ret = false;
2407
2408         if (ibuf == NULL) {
2409                 ED_space_image_release_buffer(sima, ibuf, lock);
2410                 return false;
2411         }
2412
2413         UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
2414
2415         if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2416                 const float *fp;
2417                 unsigned char *cp;
2418                 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2419
2420                 CLAMP(x, 0, ibuf->x - 1);
2421                 CLAMP(y, 0, ibuf->y - 1);
2422
2423                 if (ibuf->rect_float) {
2424                         fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
2425                         copy_v3_v3(r_col, fp);
2426                         ret = true;
2427                 }
2428                 else if (ibuf->rect) {
2429                         cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
2430                         rgb_uchar_to_float(r_col, cp);
2431                         IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
2432                         ret = true;
2433                 }
2434         }
2435
2436         if (ret) {
2437                 IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
2438         }
2439
2440         ED_space_image_release_buffer(sima, ibuf, lock);
2441         return ret;
2442 }
2443
2444 static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
2445 {
2446         SpaceImage *sima = CTX_wm_space_image(C);
2447         ARegion *ar = CTX_wm_region(C);
2448         void *lock;
2449         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2450         ImageSampleInfo *info = op->customdata;
2451         float fx, fy;
2452         Scene *scene = CTX_data_scene(C);
2453         CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
2454
2455         if (ibuf == NULL) {
2456                 ED_space_image_release_buffer(sima, ibuf, lock);
2457                 info->draw = 0;
2458                 return;
2459         }
2460
2461         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
2462
2463         if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
2464                 const float *fp;
2465                 unsigned char *cp;
2466                 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
2467                 Image *image = ED_space_image(sima);
2468
2469                 CLAMP(x, 0, ibuf->x - 1);
2470                 CLAMP(y, 0, ibuf->y - 1);
2471
2472                 info->x = x;
2473                 info->y = y;
2474                 info->draw = 1;
2475                 info->channels = ibuf->channels;
2476
2477                 info->colp = NULL;
2478                 info->colfp = NULL;
2479                 info->zp = NULL;
2480                 info->zfp = NULL;
2481
2482                 info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
2483
2484                 if (ibuf->rect) {
2485                         cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
2486
2487                         info->col[0] = cp[0];
2488                         info->col[1] = cp[1];
2489                         info->col[2] = cp[2];
2490                         info->col[3] = cp[3];
2491                         info->colp = info->col;
2492
2493                         info->colf[0] = (float)cp[0] / 255.0f;
2494                         info->colf[1] = (float)cp[1] / 255.0f;
2495                         info->colf[2] = (float)cp[2] / 255.0f;
2496                         info->colf[3] = (float)cp[3] / 255.0f;
2497                         info->colfp = info->colf;
2498
2499                         copy_v4_v4(info->linearcol, info->colf);
2500                         IMB_colormanagement_colorspace_to_scene_linear_v4(info->linearcol, false, ibuf->rect_colorspace);
2501
2502                         info->color_manage = true;
2503                 }
2504                 if (ibuf->rect_float) {
2505                         fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
2506
2507                         info->colf[0] = fp[0];
2508                         info->colf[1] = fp[1];
2509                         info->colf[2] = fp[2];
2510                         info->colf[3] = fp[3];
2511                         info->colfp = info->colf;
2512
2513                         copy_v4_v4(info->linearcol, info->colf);
2514
2515                         info->color_manage = true;
2516                 }
2517
2518                 if (ibuf->zbuf) {
2519                         info->z = ibuf->zbuf[y * ibuf->x + x];
2520                         info->zp = &info->z;
2521                 }
2522                 if (ibuf->zbuf_float) {
2523                         info->zf = ibuf->zbuf_float[y * ibuf->x + x];
2524                         info->zfp = &info->zf;
2525                 }
2526
2527                 if (curve_mapping && ibuf->channels == 4) {
2528                         /* we reuse this callback for set curves point operators */
2529                         if (RNA_struct_find_property(op->ptr, "point")) {
2530                                 int point = RNA_enum_get(op->ptr, "point");
2531
2532                                 if (point == 1) {
2533                                         curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
2534                                 }
2535                                 else if (point == 0) {
2536                                         curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
2537                                 }
2538                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
2539                         }
2540                 }
2541
2542                 // XXX node curve integration ..
2543 #if 0
2544                 {
2545                         ScrArea *sa, *cur = curarea;
2546                         
2547                         node_curvemap_sample(fp);   /* sends global to node editor */
2548                         for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
2549                                 if (sa->spacetype == SPACE_NODE) {
2550                                         areawinset(sa->win);
2551                                         scrarea_do_windraw(sa);
2552                                 }
2553                         }
2554                         node_curvemap_sample(NULL);     /* clears global in node editor */
2555                         curarea = cur;
2556                 }
2557 #endif
2558         }
2559         else {
2560                 info->draw = 0;
2561         }
2562
2563         ED_space_image_release_buffer(sima, ibuf, lock);
2564         ED_area_tag_redraw(CTX_wm_area(C));
2565 }
2566
2567 static void image_sample_exit(bContext *C, wmOperator *op)
2568 {
2569         ImageSampleInfo *info = op->customdata;
2570
2571         ED_region_draw_cb_exit(info->art, info->draw_handle);
2572         ED_area_tag_redraw(CTX_wm_area(C));
2573         MEM_freeN(info);
2574 }
2575
2576 static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2577 {
2578         SpaceImage *sima = CTX_wm_space_image(C);
2579         ARegion *ar = CTX_wm_region(C);
2580         ImageSampleInfo *info;
2581
2582         if (ar->regiontype == RGN_TYPE_WINDOW) {
2583                 if (event->mval[1] <= 16)
2584                         return OPERATOR_PASS_THROUGH;
2585         }
2586
2587         if (!ED_space_image_has_buffer(sima))
2588                 return OPERATOR_CANCELLED;
2589         
2590         info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
2591         info->art = ar->type;
2592         info->draw_handle = ED_region_draw_cb_activate(ar->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
2593         op->customdata = info;
2594
2595         image_sample_apply(C, op, event);
2596
2597         WM_event_add_modal_handler(C, op);
2598
2599         return OPERATOR_RUNNING_MODAL;
2600 }
2601
2602 static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
2603 {
2604         switch (event->type) {
2605                 case LEFTMOUSE:
2606                 case RIGHTMOUSE: // XXX hardcoded
2607                         image_sample_exit(C, op);
2608                         return OPERATOR_CANCELLED;
2609                 case MOUSEMOVE:
2610                         image_sample_apply(C, op, event);
2611                         break;
2612         }
2613
2614         return OPERATOR_RUNNING_MODAL;
2615 }
2616
2617 static void image_sample_cancel(bContext *C, wmOperator *op)
2618 {
2619         image_sample_exit(C, op);
2620 }
2621
2622 void IMAGE_OT_sample(wmOperatorType *ot)
2623 {
2624         /* identifiers */
2625         ot->name = "Sample Color";
2626         ot->idname = "IMAGE_OT_sample";
2627         ot->description = "Use mouse to sample a color in current image";
2628         
2629         /* api callbacks */
2630         ot->invoke = image_sample_invoke;
2631         ot->modal = image_sample_modal;
2632         ot->cancel = image_sample_cancel;
2633         ot->poll = image_sample_poll;
2634
2635         /* flags */
2636         ot->flag = OPTYPE_BLOCKING;
2637 }
2638
2639 /******************** sample line operator ********************/
2640 static int image_sample_line_exec(bContext *C, wmOperator *op)
2641 {
2642         SpaceImage *sima = CTX_wm_space_image(C);
2643         ARegion *ar = CTX_wm_region(C);
2644         Scene *scene = CTX_data_scene(C);
2645
2646         int x_start = RNA_int_get(op->ptr, "xstart");
2647         int y_start = RNA_int_get(op->ptr, "ystart");
2648         int x_end = RNA_int_get(op->ptr, "xend");
2649         int y_end = RNA_int_get(op->ptr, "yend");
2650         
2651         void *lock;
2652         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2653         Histogram *hist = &sima->sample_line_hist;
2654         
2655         float x1f, y1f, x2f, y2f;
2656         
2657         if (ibuf == NULL) {
2658                 ED_space_image_release_buffer(sima, ibuf, lock);
2659                 return OPERATOR_CANCELLED;
2660         }
2661         /* hmmmm */
2662         if (ibuf->channels < 3) {
2663                 ED_space_image_release_buffer(sima, ibuf, lock);
2664                 return OPERATOR_CANCELLED;
2665         }
2666         
2667         UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
2668         UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
2669
2670         hist->co[0][0] = x1f;
2671         hist->co[0][1] = y1f;
2672         hist->co[1][0] = x2f;
2673         hist->co[1][1] = y2f;
2674
2675         /* enable line drawing */
2676         hist->flag |= HISTO_FLAG_SAMPLELINE;
2677
2678         BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
2679         
2680         /* reset y zoom */
2681         hist->ymax = 1.0f;
2682
2683         ED_space_image_release_buffer(sima, ibuf, lock);
2684         
2685         ED_area_tag_redraw(CTX_wm_area(C));
2686         
2687         return OPERATOR_FINISHED;
2688 }
2689
2690 static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2691 {
2692         SpaceImage *sima = CTX_wm_space_image(C);
2693
2694         Histogram *hist = &sima->sample_line_hist;
2695         hist->flag &= ~HISTO_FLAG_SAMPLELINE;
2696
2697         if (!ED_space_image_has_buffer(sima))
2698                 return OPERATOR_CANCELLED;
2699         
2700         return WM_gesture_straightline_invoke(C, op, event);
2701 }
2702
2703 void IMAGE_OT_sample_line(wmOperatorType *ot)
2704 {
2705         /* identifiers */
2706         ot->name = "Sample Line";
2707         ot->idname = "IMAGE_OT_sample_line";
2708         ot->description = "Sample a line and show it in Scope panels";
2709         
2710         /* api callbacks */
2711         ot->invoke = image_sample_line_invoke;
2712         ot->modal = WM_gesture_straightline_modal;
2713         ot->exec = image_sample_line_exec;
2714         ot->poll = space_image_main_area_poll;
2715         ot->cancel = WM_gesture_straightline_cancel;
2716         
2717         /* flags */
2718         ot->flag = 0; /* no undo/register since this operates on the space */
2719         
2720         WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
2721 }
2722
2723 /******************** set curve point operator ********************/
2724
2725 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
2726 {
2727         static EnumPropertyItem point_items[] = {
2728                 {0, "BLACK_POINT", 0, "Black Point", ""},
2729                 {1, "WHITE_POINT", 0, "White Point", ""},
2730                 {0, NULL, 0, NULL, NULL}
2731         };
2732
2733         /* identifiers */
2734         ot->name = "Set Curves Point";
2735         ot->idname = "IMAGE_OT_curves_point_set";
2736         ot->description = "Set black point or white point for curves";
2737
2738         /* flags */
2739         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2740         
2741         /* api callbacks */
2742         ot->invoke = image_sample_invoke;
2743         ot->modal = image_sample_modal;
2744         ot->cancel = image_sample_cancel;
2745         ot->poll = space_image_main_area_not_uv_brush_poll;
2746
2747         /* properties */
2748         RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
2749 }
2750
2751 #if 0 /* Not ported to 2.5x yet */
2752 /******************** record composite operator *********************/
2753
2754 typedef struct RecordCompositeData {
2755         wmTimer *timer;
2756         int old_cfra;
2757         int sfra, efra;
2758 } RecordCompositeData;
2759
2760 static int image_record_composite_apply(bContext *C, wmOperator *op)
2761 {
2762         SpaceImage *sima = CTX_wm_space_image(C);
2763         RecordCompositeData *rcd = op->customdata;
2764         Scene *scene = CTX_data_scene(C);
2765         ImBuf *ibuf;
2766         
2767         WM_cursor_time(CTX_wm_window(C), scene->r.cfra);
2768
2769         // XXX scene->nodetree->test_break = blender_test_break;
2770         // XXX scene->nodetree->test_break = NULL;
2771         
2772         BKE_image_all_free_anim_ibufs(scene->r.cfra);
2773         ntreeCompositTagAnimated(scene->nodetree);
2774         ntreeCompositExecTree(scene->nodetree, &scene->r, 0, scene->r.cfra != rcd->old_cfra,
2775                               &scene->view_settings, &scene->display_settings);  /* 1 is no previews */
2776
2777         ED_area_tag_redraw(CTX_wm_area(C));
2778         
2779         ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, NULL);
2780         /* save memory in flipbooks */
2781         if (ibuf)
2782                 imb_freerectfloatImBuf(ibuf);
2783
2784         BKE_image_release_ibuf(sima->image, ibuf, NULL);
2785
2786         scene->r.cfra++;
2787
2788         return (scene->r.cfra <= rcd->efra);
2789 }
2790
2791 static int image_record_composite_init(bContext *C, wmOperator *op)
2792 {
2793         SpaceImage *sima = CTX_wm_space_image(C);
2794         Scene *scene = CTX_data_scene(C);
2795         RecordCompositeData *rcd;
2796
2797         if (sima->iuser.frames < 2)
2798                 return 0;
2799         if (scene->nodetree == NULL)
2800                 return 0;
2801         
2802         op->customdata = rcd = MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData");
2803
2804         rcd->old_cfra = scene->r.cfra;
2805         rcd->sfra = sima->iuser.sfra;
2806         rcd->efra = sima->iuser.sfra + sima->iuser.frames - 1;
2807         scene->r.cfra = rcd->sfra;
2808
2809         return 1;
2810 }
2811
2812 static void image_record_composite_exit(bContext *C, wmOperator *op)
2813 {
2814         Scene *scene = CTX_data_scene(C);
2815         SpaceImage *sima = CTX_wm_space_image(C);
2816         RecordCompositeData *rcd = op->customdata;
2817
2818         scene->r.cfra = rcd->old_cfra;
2819
2820         WM_cursor_modal_restore(CTX_wm_window(C));
2821
2822         if (rcd->timer)
2823                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer);
2824
2825         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
2826
2827         // XXX play_anim(0);
2828         // XXX allqueue(REDRAWNODE, 1);
2829
2830         MEM_freeN(rcd);
2831 }
2832
2833 static int image_record_composite_exec(bContext *C, wmOperator *op)
2834 {
2835         if (!image_record_composite_init(C, op))
2836                 return OPERATOR_CANCELLED;
2837         
2838         while (image_record_composite_apply(C, op)) {}
2839         
2840         image_record_composite_exit(C, op);
2841         
2842         return OPERATOR_FINISHED;
2843 }
2844
2845 static int image_record_composite_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2846 {
2847         RecordCompositeData *rcd;
2848         
2849         if (!image_record_composite_init(C, op))
2850                 return OPERATOR_CANCELLED;
2851
2852         rcd = op->customdata;
2853         rcd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.0f);
2854         WM_event_add_modal_handler(C, op);
2855
2856         if (!image_record_composite_apply(C, op))
2857                 return OPERATOR_FINISHED;
2858
2859         return OPERATOR_RUNNING_MODAL;
2860 }
2861
2862 static int image_record_composite_modal(bContext *C, wmOperator *op, const wmEvent *event)
2863 {
2864         RecordCompositeData *rcd = op->customdata;
2865
2866         switch (event->type) {
2867                 case TIMER:
2868                         if (rcd->timer == event->customdata) {
2869                                 if (!image_record_composite_apply(C, op)) {
2870                                         image_record_composite_exit(C, op);
2871                                         return OPERATOR_FINISHED;
2872                                 }
2873                         }
2874                         break;
2875                 case ESCKEY:
2876                         image_record_composite_exit(C, op);
2877                         return OPERATOR_FINISHED;
2878         }
2879
2880         return OPERATOR_RUNNING_MODAL;
2881 }
2882
2883 static void image_record_composite_cancel(bContext *C, wmOperator *op)
2884 {
2885         image_record_composite_exit(C, op);
2886         return OPERATOR_CANCELLED;
2887 }
2888
2889 void IMAGE_OT_record_composite(wmOperatorType *ot)
2890 {
2891         /* identifiers */
2892         ot->name = "Record Composite";
2893         ot->idname = "IMAGE_OT_record_composite";
2894         
2895         /* api callbacks */
2896         ot->exec = image_record_composite_exec;
2897         ot->invoke = image_record_composite_invoke;
2898         ot->modal = image_record_composite_modal;
2899         ot->cancel = image_record_composite_cancel;
2900         ot->poll = space_image_buffer_exists_poll;
2901 }
2902
2903 #endif
2904
2905 /********************* cycle render slot operator *********************/
2906
2907 static int image_cycle_render_slot_poll(bContext *C)
2908 {
2909         Image *ima = CTX_data_edit_image(C);
2910
2911         return (ima && ima->type == IMA_TYPE_R_RESULT);
2912 }
2913
2914 static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
2915 {
2916         Image *ima = CTX_data_edit_image(C);
2917         int a, slot, cur = ima->render_slot;
2918         const bool use_reverse = RNA_boolean_get(op->ptr, "reverse");
2919
2920         for (a = 1; a < IMA_MAX_RENDER_SLOT; a++) {
2921                 slot = (cur + (use_reverse ? -a : a)) % IMA_MAX_RENDER_SLOT;
2922                 if (slot < 0) slot += IMA_MAX_RENDER_SLOT;
2923
2924                 if (ima->renders[slot] || slot == ima->last_render_slot) {
2925                         ima->render_slot = slot;
2926                         break;
2927                 }
2928         }
2929
2930         if (a == IMA_MAX_RENDER_SLOT)
2931                 ima->render_slot = ((cur == 1) ? 0 : 1);
2932         
2933         WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
2934
2935         /* no undo push for browsing existing */
2936         if (ima->renders[ima->render_slot] || ima->render_slot == ima->last_render_slot)
2937                 return OPERATOR_CANCELLED;
2938         
2939         return OPERATOR_FINISHED;
2940 }
2941
2942 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
2943 {
2944         /* identifiers */
2945         ot->name = "Cycle Render Slot";
2946         ot->idname = "IMAGE_OT_cycle_render_slot";
2947         ot->description = "Cycle through all non-void render slots";
2948         
2949         /* api callbacks */
2950         ot->exec = image_cycle_render_slot_exec;
2951         ot->poll = image_cycle_render_slot_poll;
2952
2953         /* flags */
2954         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2955
2956         RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
2957 }
2958
2959 /********************** change frame operator *********************/
2960
2961 static int change_frame_poll(bContext *C)
2962 {
2963         /* prevent changes during render */
2964         if (G.is_rendering)
2965                 return 0;
2966
2967         return space_image_main_area_poll(C);
2968 }
2969
2970 static void change_frame_apply(bContext *C, wmOperator *op)
2971 {
2972         Scene *scene = CTX_data_scene(C);
2973
2974         /* set the new frame number */
2975         CFRA = RNA_int_get(op->ptr, "frame");
2976         FRAMENUMBER_MIN_CLAMP(CFRA);
2977         SUBFRA = 0.0f;
2978
2979         /* do updates */
2980         sound_seek_scene(CTX_data_main(C), scene);
2981         WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
2982 }
2983
2984 static int change_frame_exec(bContext *C, wmOperator *op)
2985 {
2986         change_frame_apply(C, op);
2987
2988         return OPERATOR_FINISHED;
2989 }
2990
2991 static int frame_from_event(bContext *C, const wmEvent *event)
2992 {
2993         ARegion *ar = CTX_wm_region(C);
2994         Scene *scene = CTX_data_scene(C);
2995         int framenr = 0;
2996
2997         if (ar->regiontype == RGN_TYPE_WINDOW) {
2998                 float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
2999
3000                 framenr = sfra + event->mval[0] / framelen;
3001         }
3002         else {
3003                 float viewx, viewy;
3004
3005                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
3006
3007                 framenr = iroundf(viewx);
3008         }
3009
3010         return framenr;
3011 }
3012
3013 static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3014 {
3015         ARegion *ar = CTX_wm_region(C);
3016
3017         if (ar->regiontype == RGN_TYPE_WINDOW) {
3018                 if (event->mval[1] > 16)
3019                         return OPERATOR_PASS_THROUGH;
3020         }
3021
3022         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3023
3024         change_frame_apply(C, op);
3025
3026         /* add temp handler */
3027         WM_event_add_modal_handler(C, op);
3028
3029         return OPERATOR_RUNNING_MODAL;
3030 }
3031
3032 static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
3033 {
3034         switch (event->type) {
3035                 case ESCKEY:
3036                         return OPERATOR_FINISHED;
3037
3038                 case MOUSEMOVE:
3039                         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
3040                         change_frame_apply(C, op);
3041                         break;
3042
3043                 case LEFTMOUSE:
3044                 case RIGHTMOUSE:
3045                         if (event->val == KM_RELEASE)
3046                                 return OPERATOR_FINISHED;
3047                         break;
3048         }
3049
3050         return OPERATOR_RUNNING_MODAL;
3051 }
3052
3053 void IMAGE_OT_change_frame(wmOperatorType *ot)
3054 {
3055         /* identifiers */
3056         ot->name = "Change Frame";
3057         ot->idname = "IMAGE_OT_change_frame";
3058         ot->description = "Interactively change the current frame number";
3059
3060         /* api callbacks */
3061         ot->exec = change_frame_exec;
3062         ot->invoke = change_frame_invoke;
3063         ot->modal = change_frame_modal;
3064         ot->poll = change_frame_poll;
3065
3066         /* flags */
3067         ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
3068
3069         /* rna */
3070         RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
3071 }
3072
3073 /* Reload cached render results... */
3074 /* goes over all scenes, reads render layers */
3075 static int image_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
3076 {
3077         Scene *scene = CTX_data_scene(C);
3078         SpaceImage *sima = CTX_wm_space_image(C);
3079         Image *ima;
3080
3081         ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
3082         if (sima->image == NULL) {
3083                 ED_space_image_set(sima, scene, NULL, ima);
3084         }
3085
3086         RE_ReadRenderResult(scene, scene);
3087
3088         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
3089         return OPERATOR_FINISHED;
3090 }
3091
3092 void IMAGE_OT_read_renderlayers(wmOperatorType *ot)
3093 {
3094         ot->name = "Read Render Layers";
3095         ot->idname = "IMAGE_OT_read_renderlayers";
3096         ot->description = "Read all the current scene's render layers from cache, as needed";
3097
3098         ot->poll = space_image_main_area_poll;
3099         ot->exec = image_read_renderlayers_exec;
3100
3101         /* flags */
3102         ot->flag = 0;
3103 }