Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / interface / interface_eyedropper_color.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) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file blender/editors/interface/interface_eyedropper_color.c
25  *  \ingroup edinterface
26  *
27  * Eyedropper (RGB Color)
28  *
29  * Defines:
30  * - #UI_OT_eyedropper_color
31  */
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_space_types.h"
36 #include "DNA_screen_types.h"
37
38 #include "BLI_math_vector.h"
39 #include "BLI_string.h"
40
41 #include "BKE_context.h"
42 #include "BKE_main.h"
43 #include "BKE_screen.h"
44
45 #include "RNA_access.h"
46
47 #include "BIF_gl.h"
48
49 #include "UI_interface.h"
50
51 #include "IMB_colormanagement.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "interface_intern.h"
57
58 #include "ED_image.h"
59 #include "ED_node.h"
60 #include "ED_clip.h"
61
62 #include "interface_eyedropper_intern.h"
63
64 typedef struct Eyedropper {
65         struct ColorManagedDisplay *display;
66
67         PointerRNA ptr;
68         PropertyRNA *prop;
69         int index;
70
71         float init_col[3]; /* for resetting on cancel */
72
73         bool  accum_start; /* has mouse been pressed */
74         float accum_col[3];
75         int   accum_tot;
76
77         bool accumulate; /* Color picking for cryptomatte, without accumulation. */
78 } Eyedropper;
79
80 static bool eyedropper_init(bContext *C, wmOperator *op)
81 {
82         Scene *scene = CTX_data_scene(C);
83         Eyedropper *eye;
84
85         op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
86         eye->accumulate = !STREQ(op->type->idname, "UI_OT_eyedropper_color_crypto");
87
88         UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
89
90         if ((eye->ptr.data == NULL) ||
91             (eye->prop == NULL) ||
92             (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
93             (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
94             (RNA_property_type(eye->prop) != PROP_FLOAT))
95         {
96                 return false;
97         }
98
99         if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
100                 const char *display_device;
101                 float col[4];
102
103                 display_device = scene->display_settings.display_device;
104                 eye->display = IMB_colormanagement_display_get_named(display_device);
105
106                 /* store inital color */
107                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
108                 if (eye->display) {
109                         IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
110                 }
111                 copy_v3_v3(eye->init_col, col);
112         }
113
114         return true;
115 }
116
117 static void eyedropper_exit(bContext *C, wmOperator *op)
118 {
119         WM_cursor_modal_restore(CTX_wm_window(C));
120
121         if (op->customdata) {
122                 MEM_freeN(op->customdata);
123                 op->customdata = NULL;
124         }
125 }
126
127 /* *** eyedropper_color_ helper functions *** */
128
129 /**
130  * \brief get the color from the screen.
131  *
132  * Special check for image or nodes where we MAY have HDR pixels which don't display.
133  *
134  * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
135  */
136 void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
137 {
138         /* we could use some clever */
139         Main *bmain = CTX_data_main(C);
140         bScreen *screen = CTX_wm_screen(C);
141         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
142         const char *display_device = CTX_data_scene(C)->display_settings.display_device;
143         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
144
145         if (sa) {
146                 if (sa->spacetype == SPACE_IMAGE) {
147                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
148                         if (ar) {
149                                 SpaceImage *sima = sa->spacedata.first;
150                                 int mval[2] = {mx - ar->winrct.xmin,
151                                                my - ar->winrct.ymin};
152
153                                 if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
154                                         return;
155                                 }
156                         }
157                 }
158                 else if (sa->spacetype == SPACE_NODE) {
159                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
160                         if (ar) {
161                                 SpaceNode *snode = sa->spacedata.first;
162                                 int mval[2] = {mx - ar->winrct.xmin,
163                                                my - ar->winrct.ymin};
164
165                                 if (ED_space_node_color_sample(bmain, snode, ar, mval, r_col)) {
166                                         return;
167                                 }
168                         }
169                 }
170                 else if (sa->spacetype == SPACE_CLIP) {
171                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
172                         if (ar) {
173                                 SpaceClip *sc = sa->spacedata.first;
174                                 int mval[2] = {mx - ar->winrct.xmin,
175                                                my - ar->winrct.ymin};
176
177                                 if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
178                                         return;
179                                 }
180                         }
181                 }
182         }
183
184         /* fallback to simple opengl picker */
185         glReadBuffer(GL_FRONT);
186         glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
187         glReadBuffer(GL_BACK);
188
189         IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
190 }
191
192 /* sets the sample color RGB, maintaining A */
193 static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
194 {
195         float col_conv[4];
196
197         /* to maintain alpha */
198         RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
199
200         /* convert from linear rgb space to display space */
201         if (eye->display) {
202                 copy_v3_v3(col_conv, col);
203                 IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
204         }
205         else {
206                 copy_v3_v3(col_conv, col);
207         }
208
209         RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
210
211         RNA_property_update(C, &eye->ptr, eye->prop);
212 }
213
214 static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
215 {
216         /* Accumulate color. */
217         float col[3];
218         eyedropper_color_sample_fl(C, mx, my, col);
219
220         if (eye->accumulate) {
221                 add_v3_v3(eye->accum_col, col);
222                 eye->accum_tot++;
223         }
224         else {
225                 copy_v3_v3(eye->accum_col, col);
226                 eye->accum_tot = 1;
227         }
228
229         /* Apply to property. */
230         float accum_col[3];
231         if (eye->accum_tot > 1) {
232                 mul_v3_v3fl(accum_col, eye->accum_col, 1.0f / (float)eye->accum_tot);
233         }
234         else {
235                 copy_v3_v3(accum_col, eye->accum_col);
236         }
237         eyedropper_color_set(C, eye, accum_col);
238 }
239
240 static void eyedropper_cancel(bContext *C, wmOperator *op)
241 {
242         Eyedropper *eye = op->customdata;
243         eyedropper_color_set(C, eye, eye->init_col);
244         eyedropper_exit(C, op);
245 }
246
247 /* main modal status check */
248 static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
249 {
250         Eyedropper *eye = (Eyedropper *)op->customdata;
251
252         /* handle modal keymap */
253         if (event->type == EVT_MODAL_MAP) {
254                 switch (event->val) {
255                         case EYE_MODAL_CANCEL:
256                                 eyedropper_cancel(C, op);
257                                 return OPERATOR_CANCELLED;
258                         case EYE_MODAL_SAMPLE_CONFIRM:
259                                 if (eye->accum_tot == 0) {
260                                         eyedropper_color_sample(C, eye, event->x, event->y);
261                                 }
262                                 eyedropper_exit(C, op);
263                                 return OPERATOR_FINISHED;
264                         case EYE_MODAL_SAMPLE_BEGIN:
265                                 /* enable accum and make first sample */
266                                 eye->accum_start = true;
267                                 eyedropper_color_sample(C, eye, event->x, event->y);
268                                 break;
269                         case EYE_MODAL_SAMPLE_RESET:
270                                 eye->accum_tot = 0;
271                                 zero_v3(eye->accum_col);
272                                 eyedropper_color_sample(C, eye, event->x, event->y);
273                                 break;
274                 }
275         }
276         else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
277                 if (eye->accum_start) {
278                         /* button is pressed so keep sampling */
279                         eyedropper_color_sample(C, eye, event->x, event->y);
280                 }
281         }
282
283         return OPERATOR_RUNNING_MODAL;
284 }
285
286 /* Modal Operator init */
287 static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
288 {
289         /* init */
290         if (eyedropper_init(C, op)) {
291                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
292
293                 /* add temp handler */
294                 WM_event_add_modal_handler(C, op);
295
296                 return OPERATOR_RUNNING_MODAL;
297         }
298         else {
299                 eyedropper_exit(C, op);
300                 return OPERATOR_CANCELLED;
301         }
302 }
303
304 /* Repeat operator */
305 static int eyedropper_exec(bContext *C, wmOperator *op)
306 {
307         /* init */
308         if (eyedropper_init(C, op)) {
309
310                 /* do something */
311
312                 /* cleanup */
313                 eyedropper_exit(C, op);
314
315                 return OPERATOR_FINISHED;
316         }
317         else {
318                 return OPERATOR_CANCELLED;
319         }
320 }
321
322 static bool eyedropper_poll(bContext *C)
323 {
324         /* Actual test for active button happens later, since we don't
325          * know which one is active until mouse over. */
326         return (CTX_wm_window(C) != NULL);
327 }
328
329 void UI_OT_eyedropper_color(wmOperatorType *ot)
330 {
331         /* identifiers */
332         ot->name = "Eyedropper";
333         ot->idname = "UI_OT_eyedropper_color";
334         ot->description = "Sample a color from the Blender Window to store in a property";
335
336         /* api callbacks */
337         ot->invoke = eyedropper_invoke;
338         ot->modal = eyedropper_modal;
339         ot->cancel = eyedropper_cancel;
340         ot->exec = eyedropper_exec;
341         ot->poll = eyedropper_poll;
342
343         /* flags */
344         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
345 }
346
347 void UI_OT_eyedropper_color_crypto(wmOperatorType *ot)
348 {
349         /* identifiers */
350         ot->name = "Cryptomatte Eyedropper";
351         ot->idname = "UI_OT_eyedropper_color_crypto";
352         ot->description = "Pick a color from Cryptomatte node Pick output image";
353
354         /* api callbacks */
355         ot->invoke = eyedropper_invoke;
356         ot->modal = eyedropper_modal;
357         ot->cancel = eyedropper_cancel;
358         ot->exec = eyedropper_exec;
359         ot->poll = eyedropper_poll;
360
361         /* flags */
362         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
363 }