1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup edutil
22  */
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_rect.h"
27 
28 #include "BKE_colortools.h"
29 #include "BKE_context.h"
30 #include "BKE_image.h"
31 #include "BKE_main.h"
32 #include "BKE_screen.h"
33 #include "BKE_sequencer.h"
34 
35 #include "ED_image.h"
36 #include "ED_screen.h"
37 #include "ED_space_api.h"
38 
39 #include "GPU_immediate.h"
40 #include "GPU_state.h"
41 
42 #include "IMB_colormanagement.h"
43 #include "IMB_imbuf.h"
44 #include "IMB_imbuf_types.h"
45 
46 #include "UI_view2d.h"
47 
48 #include "WM_api.h"
49 #include "WM_types.h"
50 
51 #include "sequencer_intern.h"
52 
53 /* Own define. */
54 #include "ED_util_imbuf.h"
55 
56 /* -------------------------------------------------------------------- */
57 /** \name Image Pixel Sample Struct (Operator Custom Data)
58  * \{ */
59 
60 typedef struct ImageSampleInfo {
61   ARegionType *art;
62   void *draw_handle;
63   int x, y;
64   int channels;
65 
66   int width, height;
67   int sample_size;
68 
69   unsigned char col[4];
70   float colf[4];
71   float linearcol[4];
72   int z;
73   float zf;
74 
75   unsigned char *colp;
76   const float *colfp;
77   int *zp;
78   float *zfp;
79 
80   bool draw;
81   bool color_manage;
82   int use_default_view;
83 } ImageSampleInfo;
84 
85 /** \} */
86 
87 /* -------------------------------------------------------------------- */
88 /** \name Image Pixel Sample
89  * \{ */
90 
image_sample_pixel_color_ubyte(const ImBuf * ibuf,const int coord[2],uchar r_col[4],float r_col_linear[4])91 static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
92                                            const int coord[2],
93                                            uchar r_col[4],
94                                            float r_col_linear[4])
95 {
96   const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
97   copy_v4_v4_uchar(r_col, cp);
98   rgba_uchar_to_float(r_col_linear, r_col);
99   IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
100 }
101 
image_sample_pixel_color_float(ImBuf * ibuf,const int coord[2],float r_col[4])102 static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
103 {
104   const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
105   copy_v4_v4(r_col, cp);
106 }
107 
108 /** \} */
109 
110 /* -------------------------------------------------------------------- */
111 /** \name Image Pixel Region Sample
112  * \{ */
113 
image_sample_rect_color_ubyte(const ImBuf * ibuf,const rcti * rect,uchar r_col[4],float r_col_linear[4])114 static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
115                                           const rcti *rect,
116                                           uchar r_col[4],
117                                           float r_col_linear[4])
118 {
119   uint col_accum_ub[4] = {0, 0, 0, 0};
120   zero_v4(r_col_linear);
121   int col_tot = 0;
122   int coord[2];
123   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
124     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
125       float col_temp_fl[4];
126       uchar col_temp_ub[4];
127       image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
128       add_v4_v4(r_col_linear, col_temp_fl);
129       col_accum_ub[0] += (uint)col_temp_ub[0];
130       col_accum_ub[1] += (uint)col_temp_ub[1];
131       col_accum_ub[2] += (uint)col_temp_ub[2];
132       col_accum_ub[3] += (uint)col_temp_ub[3];
133       col_tot += 1;
134     }
135   }
136   mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
137 
138   r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
139   r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
140   r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
141   r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
142 }
143 
image_sample_rect_color_float(ImBuf * ibuf,const rcti * rect,float r_col[4])144 static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
145 {
146   zero_v4(r_col);
147   int col_tot = 0;
148   int coord[2];
149   for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
150     for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
151       float col_temp_fl[4];
152       image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
153       add_v4_v4(r_col, col_temp_fl);
154       col_tot += 1;
155     }
156   }
157   mul_v4_fl(r_col, 1.0 / (float)col_tot);
158 }
159 
160 /** \} */
161 
162 /* -------------------------------------------------------------------- */
163 /** \name Image Pixel Sample (Internal Utilities)
164  * \{ */
165 
image_sample_apply(bContext * C,wmOperator * op,const wmEvent * event)166 static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
167 {
168   SpaceImage *sima = CTX_wm_space_image(C);
169   ARegion *region = CTX_wm_region(C);
170   Image *image = ED_space_image(sima);
171 
172   float uv[2];
173   UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
174   int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
175 
176   void *lock;
177   ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
178   ImageSampleInfo *info = op->customdata;
179   Scene *scene = CTX_data_scene(C);
180   CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
181 
182   if (ibuf == NULL) {
183     ED_space_image_release_buffer(sima, ibuf, lock);
184     info->draw = false;
185     return;
186   }
187 
188   if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
189     int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
190 
191     CLAMP(x, 0, ibuf->x - 1);
192     CLAMP(y, 0, ibuf->y - 1);
193 
194     info->width = ibuf->x;
195     info->height = ibuf->y;
196     info->x = x;
197     info->y = y;
198 
199     info->draw = true;
200     info->channels = ibuf->channels;
201 
202     info->colp = NULL;
203     info->colfp = NULL;
204     info->zp = NULL;
205     info->zfp = NULL;
206 
207     info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
208 
209     rcti sample_rect;
210     sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
211     sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
212     sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
213     sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
214 
215     if (ibuf->rect) {
216       image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
217       rgba_uchar_to_float(info->colf, info->col);
218 
219       info->colp = info->col;
220       info->colfp = info->colf;
221       info->color_manage = true;
222     }
223     if (ibuf->rect_float) {
224       image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
225 
226       if (ibuf->channels == 4) {
227         /* pass */
228       }
229       else if (ibuf->channels == 3) {
230         info->colf[3] = 1.0f;
231       }
232       else {
233         info->colf[1] = info->colf[0];
234         info->colf[2] = info->colf[0];
235         info->colf[3] = 1.0f;
236       }
237       info->colfp = info->colf;
238 
239       copy_v4_v4(info->linearcol, info->colf);
240 
241       info->color_manage = true;
242     }
243 
244     if (ibuf->zbuf) {
245       /* TODO, blend depth (not urgent). */
246       info->z = ibuf->zbuf[y * ibuf->x + x];
247       info->zp = &info->z;
248       if (ibuf->zbuf == (int *)ibuf->rect) {
249         info->colp = NULL;
250       }
251     }
252     if (ibuf->zbuf_float) {
253       /* TODO, blend depth (not urgent). */
254       info->zf = ibuf->zbuf_float[y * ibuf->x + x];
255       info->zfp = &info->zf;
256       if (ibuf->zbuf_float == ibuf->rect_float) {
257         info->colfp = NULL;
258       }
259     }
260 
261     if (curve_mapping && ibuf->channels == 4) {
262       /* we reuse this callback for set curves point operators */
263       if (RNA_struct_find_property(op->ptr, "point")) {
264         int point = RNA_enum_get(op->ptr, "point");
265 
266         if (point == 1) {
267           BKE_curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
268         }
269         else if (point == 0) {
270           BKE_curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
271         }
272         WM_event_add_notifier(C, NC_WINDOW, NULL);
273       }
274     }
275 
276     /* XXX node curve integration. */
277 #if 0
278     {
279       ScrArea *sa, *cur = curarea;
280 
281       node_curvemap_sample(fp); /* sends global to node editor */
282       for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
283         if (sa->spacetype == SPACE_NODE) {
284           areawinset(sa->win);
285           scrarea_do_windraw(sa);
286         }
287       }
288       node_curvemap_sample(NULL); /* clears global in node editor */
289       curarea = cur;
290     }
291 #endif
292   }
293   else {
294     info->draw = 0;
295   }
296 
297   ED_space_image_release_buffer(sima, ibuf, lock);
298   ED_area_tag_redraw(CTX_wm_area(C));
299 }
300 
sequencer_sample_apply(bContext * C,wmOperator * op,const wmEvent * event)301 static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
302 {
303   Main *bmain = CTX_data_main(C);
304   struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
305   Scene *scene = CTX_data_scene(C);
306   SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
307   ARegion *region = CTX_wm_region(C);
308   ImBuf *ibuf = sequencer_ibuf_get(bmain, region, depsgraph, scene, sseq, CFRA, 0, NULL);
309   ImageSampleInfo *info = op->customdata;
310   float fx, fy;
311 
312   if (ibuf == NULL) {
313     IMB_freeImBuf(ibuf);
314     info->draw = 0;
315     return;
316   }
317 
318   UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fx, &fy);
319 
320   fx /= scene->r.xasp / scene->r.yasp;
321 
322   fx += (float)scene->r.xsch / 2.0f;
323   fy += (float)scene->r.ysch / 2.0f;
324   fx *= (float)ibuf->x / (float)scene->r.xsch;
325   fy *= (float)ibuf->y / (float)scene->r.ysch;
326 
327   if (fx >= 0.0f && fy >= 0.0f && fx < ibuf->x && fy < ibuf->y) {
328     const float *fp;
329     unsigned char *cp;
330     int x = (int)fx, y = (int)fy;
331 
332     info->x = x;
333     info->y = y;
334     info->draw = 1;
335     info->channels = ibuf->channels;
336 
337     info->colp = NULL;
338     info->colfp = NULL;
339 
340     if (ibuf->rect) {
341       cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
342 
343       info->col[0] = cp[0];
344       info->col[1] = cp[1];
345       info->col[2] = cp[2];
346       info->col[3] = cp[3];
347       info->colp = info->col;
348 
349       info->colf[0] = (float)cp[0] / 255.0f;
350       info->colf[1] = (float)cp[1] / 255.0f;
351       info->colf[2] = (float)cp[2] / 255.0f;
352       info->colf[3] = (float)cp[3] / 255.0f;
353       info->colfp = info->colf;
354 
355       copy_v4_v4(info->linearcol, info->colf);
356       IMB_colormanagement_colorspace_to_scene_linear_v4(
357           info->linearcol, false, ibuf->rect_colorspace);
358 
359       info->color_manage = true;
360     }
361     if (ibuf->rect_float) {
362       fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
363 
364       info->colf[0] = fp[0];
365       info->colf[1] = fp[1];
366       info->colf[2] = fp[2];
367       info->colf[3] = fp[3];
368       info->colfp = info->colf;
369 
370       /* sequencer's image buffers are in non-linear space, need to make them linear */
371       copy_v4_v4(info->linearcol, info->colf);
372       BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->linearcol);
373 
374       info->color_manage = true;
375     }
376   }
377   else {
378     info->draw = 0;
379   }
380 
381   IMB_freeImBuf(ibuf);
382   ED_area_tag_redraw(CTX_wm_area(C));
383 }
384 
ed_imbuf_sample_apply(bContext * C,wmOperator * op,const wmEvent * event)385 static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
386 {
387   ScrArea *sa = CTX_wm_area(C);
388 
389   if (sa && sa->spacetype == SPACE_IMAGE) {
390     image_sample_apply(C, op, event);
391   }
392 
393   if (sa && sa->spacetype == SPACE_SEQ) {
394     sequencer_sample_apply(C, op, event);
395   }
396 }
397 
398 /** \} */
399 
400 /* -------------------------------------------------------------------- */
401 /** \name Image Pixel Sample (Public Operator Callback)
402  *
403  * Callbacks for the sample operator, used by sequencer and image spaces.
404  * \{ */
405 
ED_imbuf_sample_draw(const bContext * C,ARegion * region,void * arg_info)406 void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
407 {
408   ImageSampleInfo *info = arg_info;
409   if (!info->draw) {
410     return;
411   }
412 
413   Scene *scene = CTX_data_scene(C);
414   ED_image_draw_info(scene,
415                      region,
416                      info->color_manage,
417                      info->use_default_view,
418                      info->channels,
419                      info->x,
420                      info->y,
421                      info->colp,
422                      info->colfp,
423                      info->linearcol,
424                      info->zp,
425                      info->zfp);
426 
427   if (info->sample_size > 1) {
428     ScrArea *sa = CTX_wm_area(C);
429 
430     if (sa && sa->spacetype == SPACE_IMAGE) {
431 
432       const wmWindow *win = CTX_wm_window(C);
433       const wmEvent *event = win->eventstate;
434 
435       SpaceImage *sima = CTX_wm_space_image(C);
436       GPUVertFormat *format = immVertexFormat();
437       uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
438 
439       const float color[3] = {1, 1, 1};
440       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
441       immUniformColor3fv(color);
442 
443       /* TODO(campbell): lock to pixels. */
444       rctf sample_rect_fl;
445       BLI_rctf_init_pt_radius(
446           &sample_rect_fl,
447           (float[2]){event->x - region->winrct.xmin, event->y - region->winrct.ymin},
448           (float)(info->sample_size / 2.0f) * sima->zoom);
449 
450       GPU_logic_op_xor_set(true);
451 
452       GPU_line_width(1.0f);
453       imm_draw_box_wire_2d(pos,
454                            (float)sample_rect_fl.xmin,
455                            (float)sample_rect_fl.ymin,
456                            (float)sample_rect_fl.xmax,
457                            (float)sample_rect_fl.ymax);
458 
459       GPU_logic_op_xor_set(false);
460 
461       immUnbindProgram();
462     }
463   }
464 }
465 
ED_imbuf_sample_exit(bContext * C,wmOperator * op)466 void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
467 {
468   ImageSampleInfo *info = op->customdata;
469 
470   ED_region_draw_cb_exit(info->art, info->draw_handle);
471   ED_area_tag_redraw(CTX_wm_area(C));
472   MEM_freeN(info);
473 }
474 
ED_imbuf_sample_invoke(bContext * C,wmOperator * op,const wmEvent * event)475 int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
476 {
477   ARegion *region = CTX_wm_region(C);
478   ImageSampleInfo *info;
479 
480   info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
481 
482   info->art = region->type;
483   info->draw_handle = ED_region_draw_cb_activate(
484       region->type, ED_imbuf_sample_draw, info, REGION_DRAW_POST_PIXEL);
485   info->sample_size = RNA_int_get(op->ptr, "size");
486   op->customdata = info;
487 
488   ScrArea *sa = CTX_wm_area(C);
489 
490   if (sa && sa->spacetype == SPACE_IMAGE) {
491     SpaceImage *sima = CTX_wm_space_image(C);
492 
493     if (region->regiontype == RGN_TYPE_WINDOW) {
494       if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
495         return OPERATOR_PASS_THROUGH;
496       }
497     }
498 
499     if (!ED_space_image_has_buffer(sima)) {
500       return OPERATOR_CANCELLED;
501     }
502   }
503 
504   ed_imbuf_sample_apply(C, op, event);
505 
506   WM_event_add_modal_handler(C, op);
507 
508   return OPERATOR_RUNNING_MODAL;
509 }
510 
ED_imbuf_sample_modal(bContext * C,wmOperator * op,const wmEvent * event)511 int ED_imbuf_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
512 {
513   switch (event->type) {
514     case LEFTMOUSE:
515     case RIGHTMOUSE: /* XXX hardcoded */
516       if (event->val == KM_RELEASE) {
517         ED_imbuf_sample_exit(C, op);
518         return OPERATOR_CANCELLED;
519       }
520       break;
521     case MOUSEMOVE:
522       ed_imbuf_sample_apply(C, op, event);
523       break;
524   }
525 
526   return OPERATOR_RUNNING_MODAL;
527 }
528 
ED_imbuf_sample_cancel(bContext * C,wmOperator * op)529 void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
530 {
531   ED_imbuf_sample_exit(C, op);
532 }
533 
ED_imbuf_sample_poll(bContext * C)534 bool ED_imbuf_sample_poll(bContext *C)
535 {
536   ScrArea *sa = CTX_wm_area(C);
537 
538   if (sa && sa->spacetype == SPACE_IMAGE) {
539     SpaceImage *sima = CTX_wm_space_image(C);
540     if (sima == NULL) {
541       return false;
542     }
543 
544     Object *obedit = CTX_data_edit_object(C);
545     if (obedit) {
546       /* Disable when UV editing so it doesn't swallow all click events
547        * (use for setting cursor). */
548       if (ED_space_image_show_uvedit(sima, obedit)) {
549         return false;
550       }
551     }
552     else if (sima->mode != SI_MODE_VIEW) {
553       return false;
554     }
555 
556     return true;
557   }
558 
559   if (sa && sa->spacetype == SPACE_SEQ) {
560     SpaceSeq *sseq = CTX_wm_space_seq(C);
561 
562     if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
563       return false;
564     }
565 
566     return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL;
567   }
568 
569   return false;
570 }
571 
572 /** \} */
573