Blender V4.3
eyedropper_depth.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14#include "MEM_guardedalloc.h"
15
16#include "DNA_camera_types.h"
17#include "DNA_object_types.h"
18#include "DNA_screen_types.h"
19#include "DNA_space_types.h"
20#include "DNA_view3d_types.h"
21
22#include "BLI_math_vector.h"
23#include "BLI_string.h"
24
25#include "BKE_context.hh"
26#include "BKE_lib_id.hh"
27#include "BKE_report.hh"
28#include "BKE_screen.hh"
29#include "BKE_unit.hh"
30
31#include "RNA_access.hh"
32#include "RNA_define.hh"
33#include "RNA_path.hh"
34#include "RNA_prototypes.hh"
35
36#include "UI_interface.hh"
37
38#include "WM_api.hh"
39#include "WM_types.hh"
40
41#include "ED_screen.hh"
42#include "ED_space_api.hh"
43#include "ED_view3d.hh"
44
45#include "eyedropper_intern.hh"
46#include "interface_intern.hh"
47
54 bool is_undo;
55
56 bool is_set;
57 float init_depth; /* For resetting on cancel. */
58
59 bool accum_start; /* Has mouse been pressed. */
62
65 int name_pos[2];
66 char name[200];
67};
68
69static void depthdropper_draw_cb(const bContext * /*C*/, ARegion * /*region*/, void *arg)
70{
71 DepthDropper *ddr = static_cast<DepthDropper *>(arg);
73}
74
75static bool depthdropper_get_path(PointerRNA *ctx_ptr,
76 wmOperator *op,
77 const char *prop_path,
78 PointerRNA *r_ptr,
79 PropertyRNA **r_prop)
80{
81 PropertyRNA *unused_prop;
82
83 if (prop_path[0] == '\0') {
84 return false;
85 }
86
87 if (!r_prop) {
88 r_prop = &unused_prop;
89 }
90
91 /* Get rna from path. */
92 if (!RNA_path_resolve(ctx_ptr, prop_path, r_ptr, r_prop)) {
93 BKE_reportf(op->reports, RPT_ERROR, "Could not resolve path '%s'", prop_path);
94 return false;
95 }
96
97 /* Check property type. */
98 PropertyType prop_type = RNA_property_type(*r_prop);
99 if (prop_type != PROP_FLOAT) {
100 BKE_reportf(op->reports, RPT_ERROR, "Property from path '%s' is not a float", prop_path);
101 return false;
102 }
103
104 /* Success. */
105 return true;
106}
107
109{
111 PropertyRNA *prop;
112 int index_dummy;
113 uiBut *but;
114
115 /* Check if the custom prop_data_path is set. */
116 if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) &&
117 RNA_property_is_set(op->ptr, prop))
118 {
119 return true;
120 }
121
122 /* check if there's an active button taking depth value */
123 if ((CTX_wm_window(C) != nullptr) &&
124 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
125 (but->type == UI_BTYPE_NUM) && (prop != nullptr))
126 {
127 if ((RNA_property_type(prop) == PROP_FLOAT) &&
129 (RNA_property_array_check(prop) == false))
130 {
131 return true;
132 }
133 }
134 else {
136 if (rv3d && rv3d->persp == RV3D_CAMOB) {
137 View3D *v3d = CTX_wm_view3d(C);
138 if (v3d->camera && v3d->camera->data &&
139 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
140 {
141 return true;
142 }
143 }
144 }
145
146 return false;
147}
148
150{
151 DepthDropper *ddr = MEM_new<DepthDropper>(__func__);
152 PropertyRNA *prop;
153 if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) &&
154 RNA_property_is_set(op->ptr, prop))
155 {
156 char *prop_data_path = RNA_string_get_alloc(op->ptr, "prop_data_path", nullptr, 0, nullptr);
157 BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(prop_data_path); });
158 if (!prop_data_path) {
159 MEM_freeN(ddr);
160 return false;
161 }
162 PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, C);
163 if (!depthdropper_get_path(&ctx_ptr, op, prop_data_path, &ddr->ptr, &ddr->prop)) {
164 MEM_delete(ddr);
165 return false;
166 }
167 }
168 else {
169 /* fallback to the active camera's dof */
170 int index_dummy;
171 uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
172 if (ddr->prop == nullptr) {
174 if (rv3d && rv3d->persp == RV3D_CAMOB) {
175 View3D *v3d = CTX_wm_view3d(C);
176 if (v3d->camera && v3d->camera->data &&
177 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
178 {
179 Camera *camera = (Camera *)v3d->camera->data;
180 ddr->ptr = RNA_pointer_create(&camera->id, &RNA_CameraDOFSettings, &camera->dof);
181 ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance");
182 ddr->is_undo = true;
183 }
184 }
185 }
186 else {
188 }
189 }
190
191 if ((ddr->ptr.data == nullptr) || (ddr->prop == nullptr) ||
192 (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
194 {
195 MEM_delete(ddr);
196 return false;
197 }
198 op->customdata = ddr;
199
202
203 ddr->art = art;
206 ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
207
208 return true;
209}
210
212{
214
215 if (op->customdata) {
217
218 if (ddr->art) {
220 }
221 op->customdata = nullptr;
222 MEM_delete(ddr);
223 }
224}
225
226/* *** depthdropper id helper functions *** */
231 DepthDropper *ddr,
232 const int m_xy[2],
233 float *r_depth)
234{
235 /* we could use some clever */
236 bScreen *screen = CTX_wm_screen(C);
237 ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, m_xy);
238 Scene *scene = CTX_data_scene(C);
239
240 ScrArea *area_prev = CTX_wm_area(C);
241 ARegion *region_prev = CTX_wm_region(C);
242
243 ddr->name[0] = '\0';
244
245 if (area) {
246 if (area->spacetype == SPACE_VIEW3D) {
247 ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, m_xy);
248 if (region) {
250 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
251 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
252 /* weak, we could pass in some reference point */
253 const blender::float3 &view_co = (v3d->camera && rv3d->persp == RV3D_CAMOB) ?
254 v3d->camera->object_to_world().location() :
255 rv3d->viewinv[3];
256
257 const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin};
258 copy_v2_v2_int(ddr->name_pos, mval);
259
260 float co[3];
261
262 CTX_wm_area_set(C, area);
263 CTX_wm_region_set(C, region);
264
265 /* Unfortunately it's necessary to always draw otherwise we leave stale text. */
266 ED_region_tag_redraw(region);
267
269
270 /* Ensure the depth buffer is updated for #ED_view3d_autodist. */
271 ED_view3d_depth_override(depsgraph, region, v3d, nullptr, V3D_DEPTH_NO_GPENCIL, nullptr);
272
273 if (ED_view3d_autodist(region, v3d, mval, co, nullptr)) {
274 const float mval_center_fl[2] = {float(region->winx) / 2, float(region->winy) / 2};
275 float co_align[3];
276
277 /* quick way to get view-center aligned point */
278 ED_view3d_win_to_3d(v3d, region, co, mval_center_fl, co_align);
279
280 *r_depth = len_v3v3(view_co, co_align);
281
283 sizeof(ddr->name),
284 double(*r_depth),
285 4,
287 &scene->unit,
288 false);
289 }
290 else {
291 STRNCPY(ddr->name, "Nothing under cursor");
292 }
293 }
294 }
295 }
296
297 CTX_wm_area_set(C, area_prev);
298 CTX_wm_region_set(C, region_prev);
299}
300
301/* sets the sample depth RGB, maintaining A */
302static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
303{
304 RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
305 ddr->is_set = true;
306 RNA_property_update(C, &ddr->ptr, ddr->prop);
307}
308
309/* set sample from accumulated values */
311{
312 float depth = ddr->accum_depth;
313 if (ddr->accum_tot) {
314 depth /= float(ddr->accum_tot);
315 }
316 depthdropper_depth_set(C, ddr, depth);
317}
318
319/* single point sample & set */
320static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, const int m_xy[2])
321{
322 float depth = -1.0f;
323 if (depth != -1.0f) {
324 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
325 depthdropper_depth_set(C, ddr, depth);
326 }
327}
328
329static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2])
330{
331 float depth = -1.0f;
332 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
333 if (depth != -1.0f) {
334 ddr->accum_depth += depth;
335 ddr->accum_tot++;
336 }
337}
338
340{
341 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
342 if (ddr->is_set) {
344 }
345 depthdropper_exit(C, op);
346}
347
348/* main modal status check */
349static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
350{
351 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
352
353 /* handle modal keymap */
354 if (event->type == EVT_MODAL_MAP) {
355 switch (event->val) {
356 case EYE_MODAL_CANCEL:
357 depthdropper_cancel(C, op);
358 return OPERATOR_CANCELLED;
360 const bool is_undo = ddr->is_undo;
361 if (ddr->accum_tot == 0) {
362 depthdropper_depth_sample(C, ddr, event->xy);
363 }
364 else {
366 }
367 depthdropper_exit(C, op);
368 /* Could support finished & undo-skip. */
369 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
370 }
372 /* enable accum and make first sample */
373 ddr->accum_start = true;
374 depthdropper_depth_sample_accum(C, ddr, event->xy);
375 break;
377 ddr->accum_tot = 0;
378 ddr->accum_depth = 0.0f;
379 depthdropper_depth_sample_accum(C, ddr, event->xy);
381 break;
382 }
383 }
384 else if (event->type == MOUSEMOVE) {
385 if (ddr->accum_start) {
386 /* button is pressed so keep sampling */
387 depthdropper_depth_sample_accum(C, ddr, event->xy);
389 }
390 }
391
393}
394
395/* Modal Operator init */
396static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
397{
398 if (!depthdropper_test(C, op)) {
399 /* If the operator can't be executed, make sure to not consume the event. */
401 }
402 /* init */
403 if (depthdropper_init(C, op)) {
404 wmWindow *win = CTX_wm_window(C);
405 /* Workaround for de-activating the button clearing the cursor, see #76794 */
408
409 /* add temp handler */
411
413 }
414 return OPERATOR_CANCELLED;
415}
416
417/* Repeat operator */
419{
420 /* init */
421 if (depthdropper_init(C, op)) {
422 /* cleanup */
423 depthdropper_exit(C, op);
424
425 return OPERATOR_FINISHED;
426 }
427 return OPERATOR_CANCELLED;
428}
429
431{
433 PropertyRNA *prop;
434 int index_dummy;
435 uiBut *but;
436
437 /* check if there's an active button taking depth value */
438 if ((CTX_wm_window(C) != nullptr) &&
439 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)))
440 {
441 if (but->icon == ICON_EYEDROPPER) {
442 return true;
443 }
444 /* Context menu button. */
445 if (but->optype && STREQ(but->optype->idname, "UI_OT_eyedropper_depth")) {
446 return true;
447 }
448
449 if ((but->type == UI_BTYPE_NUM) && (prop != nullptr) &&
450 (RNA_property_type(prop) == PROP_FLOAT) &&
452 (RNA_property_array_check(prop) == false))
453 {
454 return true;
455 }
456 }
457 else {
459 if (rv3d && rv3d->persp == RV3D_CAMOB) {
460 View3D *v3d = CTX_wm_view3d(C);
461 if (v3d->camera && v3d->camera->data &&
462 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
463 {
464 return true;
465 }
466 }
467 }
468
469 return false;
470}
471
473{
474 /* identifiers */
475 ot->name = "Eyedropper Depth";
476 ot->idname = "UI_OT_eyedropper_depth";
477 ot->description = "Sample depth from the 3D view";
478
479 /* api callbacks */
485
486 /* flags */
488
489 /* Paths relative to the context. */
490 PropertyRNA *prop;
491 prop = RNA_def_string(ot->srna,
492 "prop_data_path",
493 nullptr,
494 0,
495 "Data Path",
496 "Path of property to be set with the depth");
498}
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2456
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
ARegion * BKE_area_find_region_xy(const ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition screen.cc:844
ScrArea ScrArea * BKE_screen_find_area_xy(const bScreen *screen, int spacetype, const int xy[2]) ATTR_NONNULL(1
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:243
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:253
@ B_UNIT_LENGTH
Definition BKE_unit.hh:107
size_t BKE_unit_value_as_string(char *str, int str_maxncpy, double value, int prec, int type, const UnitSettings *settings, bool pad)
Definition unit.cc:1876
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
#define BLI_SCOPED_DEFER(function_to_defer)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define STREQ(a, b)
Object is a sort of wrapper for general info.
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
#define SPACE_TYPE_ANY
@ RV3D_CAMOB
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
#define REGION_DRAW_POST_PIXEL
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
bool ED_view3d_autodist(ARegion *region, View3D *v3d, const int mval[2], float mouse_worldloc[3], const float fallback_depth_pt[3])
void ED_view3d_depth_override(Depsgraph *depsgraph, ARegion *region, View3D *v3d, Object *obact, eV3DDepthOverrideMode mode, ViewDepths **r_depths)
void view3d_operator_needs_opengl(const bContext *C)
@ V3D_DEPTH_NO_GPENCIL
Definition ED_view3d.hh:188
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
PropertyType
Definition RNA_types.hh:64
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_UNIT_LENGTH
Definition RNA_types.hh:77
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
uiBut * UI_context_active_but_prop_get(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
void UI_context_active_but_clear(bContext *C, wmWindow *win, ARegion *region)
@ UI_BTYPE_NUM
bool UI_but_flag_is_set(uiBut *but, int flag)
@ UI_BUT_UNDO
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
const Depsgraph * depsgraph
draw_view in_light_buf[] float
static void depthdropper_draw_cb(const bContext *, ARegion *, void *arg)
static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, const int m_xy[2], float *r_depth)
get the ID from the screen.
static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
void UI_OT_eyedropper_depth(wmOperatorType *ot)
static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, const int m_xy[2])
static int depthdropper_exec(bContext *C, wmOperator *op)
static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2])
static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void depthdropper_exit(bContext *C, wmOperator *op)
static void depthdropper_cancel(bContext *C, wmOperator *op)
static bool depthdropper_poll(bContext *C)
static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *)
static bool depthdropper_get_path(PointerRNA *ctx_ptr, wmOperator *op, const char *prop_path, PointerRNA *r_ptr, PropertyRNA **r_prop)
static bool depthdropper_test(bContext *C, wmOperator *op)
static int depthdropper_init(bContext *C, wmOperator *op)
@ EYE_MODAL_SAMPLE_BEGIN
@ EYE_MODAL_SAMPLE_RESET
@ EYE_MODAL_CANCEL
@ EYE_MODAL_SAMPLE_CONFIRM
void eyedropper_draw_cursor_text_region(const int xy[2], const char *name)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_array_check(PropertyRNA *prop)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
PropertyType RNA_property_type(PropertyRNA *prop)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
bool RNA_path_resolve(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:525
PropertyRNA * prop
ARegionType * art
Definition DNA_ID.h:413
void * data
Definition RNA_types.hh:42
float viewinv[4][4]
struct Object * camera
wmOperatorType * optype
eButType type
BIFIconID icon
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_EYEDROPPER
Definition wm_cursors.hh:35
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ EVT_MODAL_MAP
@ MOUSEMOVE
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125