Blender V4.5
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
13
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
53 PropertyRNA *prop = nullptr;
54 bool is_undo = false;
55
56 bool is_set = false;
57 float init_depth = 0.0f; /* For resetting on cancel. */
58
59 bool accum_start = false; /* Has mouse been pressed. */
60 float accum_depth = 0.0f;
61 int accum_tot = 0;
62
63 ARegionType *art = nullptr;
64 void *draw_handle_pixel = nullptr;
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_delete(ddr);
160 return false;
161 }
162 PointerRNA ctx_ptr = RNA_pointer_create_discrete(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;
181 &camera->id, &RNA_CameraDOFSettings, &camera->dof);
182 ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance");
183 ddr->is_undo = true;
184 }
185 }
186 }
187 else {
189 }
190 }
191
192 if ((ddr->ptr.data == nullptr) || (ddr->prop == nullptr) ||
193 (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
195 {
196 MEM_delete(ddr);
197 return false;
198 }
199 op->customdata = ddr;
200
203
204 ddr->art = art;
207 ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
208
209 return true;
210}
211
213{
215
216 if (op->customdata) {
218
219 if (ddr->art) {
221 }
222 op->customdata = nullptr;
223 MEM_delete(ddr);
224 }
225}
226
227/* *** depthdropper id helper functions *** */
232 DepthDropper *ddr,
233 const int m_xy[2],
234 float *r_depth)
235{
236 /* we could use some clever */
237 bScreen *screen = CTX_wm_screen(C);
238 ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, m_xy);
239 Scene *scene = CTX_data_scene(C);
240
241 ScrArea *area_prev = CTX_wm_area(C);
242 ARegion *region_prev = CTX_wm_region(C);
243
244 ddr->name[0] = '\0';
245
246 if (area) {
247 if (area->spacetype == SPACE_VIEW3D) {
248 ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, m_xy);
249 if (region) {
251 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
252 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
253 /* weak, we could pass in some reference point */
254 const blender::float3 &view_co = (v3d->camera && rv3d->persp == RV3D_CAMOB) ?
255 v3d->camera->object_to_world().location() :
256 rv3d->viewinv[3];
257
258 const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin};
259 copy_v2_v2_int(ddr->name_pos, mval);
260
261 float co[3];
262
263 CTX_wm_area_set(C, area);
264 CTX_wm_region_set(C, region);
265
266 /* Unfortunately it's necessary to always draw otherwise we leave stale text. */
267 ED_region_tag_redraw(region);
268
270
271 /* Ensure the depth buffer is updated for #ED_view3d_autodist. */
273 depsgraph, region, v3d, nullptr, V3D_DEPTH_NO_GPENCIL, false, nullptr);
274
275 if (ED_view3d_autodist(region, v3d, mval, co, nullptr)) {
276 const float mval_center_fl[2] = {float(region->winx) / 2, float(region->winy) / 2};
277 float co_align[3];
278
279 /* quick way to get view-center aligned point */
280 ED_view3d_win_to_3d(v3d, region, co, mval_center_fl, co_align);
281
282 *r_depth = len_v3v3(view_co, co_align);
283
285 sizeof(ddr->name),
286 double(*r_depth),
287 4,
289 scene->unit,
290 false);
291 }
292 else {
293 STRNCPY(ddr->name, "Nothing under cursor");
294 }
295 }
296 }
297 }
298
299 CTX_wm_area_set(C, area_prev);
300 CTX_wm_region_set(C, region_prev);
301}
302
303/* sets the sample depth RGB, maintaining A */
304static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
305{
306 RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
307 ddr->is_set = true;
308 RNA_property_update(C, &ddr->ptr, ddr->prop);
309}
310
311/* set sample from accumulated values */
313{
314 float depth = ddr->accum_depth;
315 if (ddr->accum_tot) {
316 depth /= float(ddr->accum_tot);
317 }
318 depthdropper_depth_set(C, ddr, depth);
319}
320
321/* single point sample & set */
322static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, const int m_xy[2])
323{
324 float depth = -1.0f;
325 if (depth != -1.0f) {
326 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
327 depthdropper_depth_set(C, ddr, depth);
328 }
329}
330
331static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2])
332{
333 float depth = -1.0f;
334 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
335 if (depth != -1.0f) {
336 ddr->accum_depth += depth;
337 ddr->accum_tot++;
338 }
339}
340
342{
343 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
344 if (ddr->is_set) {
346 }
347 depthdropper_exit(C, op);
348}
349
350/* main modal status check */
352{
353 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
354
355 /* handle modal keymap */
356 if (event->type == EVT_MODAL_MAP) {
357 switch (event->val) {
358 case EYE_MODAL_CANCEL:
360 return OPERATOR_CANCELLED;
362 const bool is_undo = ddr->is_undo;
363 if (ddr->accum_tot == 0) {
364 depthdropper_depth_sample(C, ddr, event->xy);
365 }
366 else {
368 }
369 depthdropper_exit(C, op);
370 /* Could support finished & undo-skip. */
371 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
372 }
374 /* enable accum and make first sample */
375 ddr->accum_start = true;
377 break;
379 ddr->accum_tot = 0;
380 ddr->accum_depth = 0.0f;
383 break;
384 }
385 }
386 else if (event->type == MOUSEMOVE) {
387 if (ddr->accum_start) {
388 /* button is pressed so keep sampling */
391 }
392 }
393
395}
396
397/* Modal Operator init */
399{
400 if (!depthdropper_test(C, op)) {
401 /* If the operator can't be executed, make sure to not consume the event. */
403 }
404 /* init */
405 if (depthdropper_init(C, op)) {
406 wmWindow *win = CTX_wm_window(C);
407 /* Workaround for de-activating the button clearing the cursor, see #76794 */
410
411 /* add temp handler */
413
415 }
416 return OPERATOR_CANCELLED;
417}
418
419/* Repeat operator */
421{
422 /* init */
423 if (depthdropper_init(C, op)) {
424 /* cleanup */
425 depthdropper_exit(C, op);
426
427 return OPERATOR_FINISHED;
428 }
429 return OPERATOR_CANCELLED;
430}
431
433{
435 PropertyRNA *prop;
436 int index_dummy;
437 uiBut *but;
438
439 /* check if there's an active button taking depth value */
440 if ((CTX_wm_window(C) != nullptr) &&
441 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)))
442 {
443 if (but->icon == ICON_EYEDROPPER) {
444 return true;
445 }
446 /* Context menu button. */
447 if (but->optype && STREQ(but->optype->idname, "UI_OT_eyedropper_depth")) {
448 return true;
449 }
450
451 if ((but->type == UI_BTYPE_NUM) && (prop != nullptr) &&
452 (RNA_property_type(prop) == PROP_FLOAT) &&
454 (RNA_property_array_check(prop) == false))
455 {
456 return true;
457 }
458 }
459 else {
461 if (rv3d && rv3d->persp == RV3D_CAMOB) {
462 View3D *v3d = CTX_wm_view3d(C);
463 if (v3d->camera && v3d->camera->data &&
464 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
465 {
466 return true;
467 }
468 }
469 }
470
471 return false;
472}
473
475{
476 /* identifiers */
477 ot->name = "Eyedropper Depth";
478 ot->idname = "UI_OT_eyedropper_depth";
479 ot->description = "Sample depth from the 3D view";
480
481 /* API callbacks. */
482 ot->invoke = depthdropper_invoke;
483 ot->modal = depthdropper_modal;
484 ot->cancel = depthdropper_cancel;
485 ot->exec = depthdropper_exec;
486 ot->poll = depthdropper_poll;
487
488 /* flags */
490
491 /* Paths relative to the context. */
492 PropertyRNA *prop;
493 prop = RNA_def_string(ot->srna,
494 "prop_data_path",
495 nullptr,
496 0,
497 "Data Path",
498 "Path of property to be set with the depth");
500}
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:2503
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:869
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:251
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:261
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
@ B_UNIT_LENGTH
Definition BKE_unit.hh:124
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)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#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_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
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_depth_override(Depsgraph *depsgraph, ARegion *region, View3D *v3d, Object *obact, eV3DDepthOverrideMode mode, bool use_overlay, ViewDepths **r_depths)
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])
@ V3D_DEPTH_NO_GPENCIL
Definition ED_view3d.hh:192
void view3d_operator_needs_gpu(const bContext *C)
Read Guarded memory(de)allocation.
PropertyType
Definition RNA_types.hh:149
@ PROP_FLOAT
Definition RNA_types.hh:152
@ PROP_UNIT_LENGTH
Definition RNA_types.hh:162
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
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
@ UI_BUT_UNDO
bool UI_but_flag_is_set(uiBut *but, int flag)
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
BPy_StructRNA * depsgraph
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 void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2])
static wmOperatorStatus depthdropper_exec(bContext *C, wmOperator *op)
static wmOperatorStatus 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 bool depthdropper_get_path(PointerRNA *ctx_ptr, wmOperator *op, const char *prop_path, PointerRNA *r_ptr, PropertyRNA **r_prop)
static wmOperatorStatus depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *)
static bool depthdropper_test(bContext *C, wmOperator *op)
static int depthdropper_init(bContext *C, wmOperator *op)
void eyedropper_draw_cursor_text_region(const int xy[2], const char *name)
@ EYE_MODAL_SAMPLE_BEGIN
@ EYE_MODAL_SAMPLE_RESET
@ EYE_MODAL_CANCEL
@ EYE_MODAL_SAMPLE_CONFIRM
#define MEM_SAFE_FREE(v)
VecBase< float, 3 > float3
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_discrete(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:532
void * regiondata
struct CameraDOFSettings dof
PropertyRNA * prop
ARegionType * art
Definition DNA_ID.h:404
void * first
void * data
Definition RNA_types.hh:53
float viewinv[4][4]
struct UnitSettings unit
ListBase spacedata
struct Object * camera
int ymin
int xmin
wmOperatorType * optype
eButType type
BIFIconID icon
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
int xy[2]
Definition WM_types.hh:758
const char * idname
Definition WM_types.hh:1032
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:36
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ EVT_MODAL_MAP
@ MOUSEMOVE
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225