Blender V5.0
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_utf8.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 "WM_api.hh"
37#include "WM_types.hh"
38
39#include "ED_screen.hh"
40#include "ED_space_api.hh"
41#include "ED_view3d.hh"
42
43#include "eyedropper_intern.hh"
44#include "interface_intern.hh"
45
51 PropertyRNA *prop = nullptr;
52 bool is_undo = false;
53
54 bool is_set = false;
55 float init_depth = 0.0f; /* For resetting on cancel. */
56
57 bool accum_start = false; /* Has mouse been pressed. */
58 float accum_depth = 0.0f;
59 int accum_tot = 0;
60
61 ARegionType *art = nullptr;
62 void *draw_handle_pixel = nullptr;
63 int name_pos[2] = {};
64 char name[200] = {};
65};
66
67static void depthdropper_draw_cb(const bContext * /*C*/, ARegion * /*region*/, void *arg)
68{
69 DepthDropper *ddr = static_cast<DepthDropper *>(arg);
71}
72
73static bool depthdropper_get_path(PointerRNA *ctx_ptr,
74 wmOperator *op,
75 const char *prop_path,
76 PointerRNA *r_ptr,
77 PropertyRNA **r_prop)
78{
79 PropertyRNA *unused_prop;
80
81 if (prop_path[0] == '\0') {
82 return false;
83 }
84
85 if (!r_prop) {
86 r_prop = &unused_prop;
87 }
88
89 /* Get rna from path. */
90 if (!RNA_path_resolve(ctx_ptr, prop_path, r_ptr, r_prop)) {
91 BKE_reportf(op->reports, RPT_ERROR, "Could not resolve path '%s'", prop_path);
92 return false;
93 }
94
95 /* Check property type. */
96 PropertyType prop_type = RNA_property_type(*r_prop);
97 if (prop_type != PROP_FLOAT) {
98 BKE_reportf(op->reports, RPT_ERROR, "Property from path '%s' is not a float", prop_path);
99 return false;
100 }
101
102 /* Success. */
103 return true;
104}
105
107{
109 PropertyRNA *prop;
110 int index_dummy;
111 uiBut *but;
112
113 /* Check if the custom prop_data_path is set. */
114 if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) &&
115 RNA_property_is_set(op->ptr, prop))
116 {
117 return true;
118 }
119
120 /* check if there's an active button taking depth value */
121 if ((CTX_wm_window(C) != nullptr) &&
122 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
123 (but->type == ButType::Num) && (prop != nullptr))
124 {
125 if ((RNA_property_type(prop) == PROP_FLOAT) &&
127 (RNA_property_array_check(prop) == false))
128 {
129 return true;
130 }
131 }
132 else {
134 if (rv3d && rv3d->persp == RV3D_CAMOB) {
135 View3D *v3d = CTX_wm_view3d(C);
136 if (v3d->camera && v3d->camera->data &&
137 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
138 {
139 return true;
140 }
141 }
142 }
143
144 return false;
145}
146
148{
149 DepthDropper *ddr = MEM_new<DepthDropper>(__func__);
150 PropertyRNA *prop;
151 if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) &&
152 RNA_property_is_set(op->ptr, prop))
153 {
154 std::string prop_data_path = RNA_string_get(op->ptr, "prop_data_path");
155 if (prop_data_path.empty()) {
156 MEM_delete(ddr);
157 return false;
158 }
159 PointerRNA ctx_ptr = RNA_pointer_create_discrete(nullptr, &RNA_Context, C);
160 if (!depthdropper_get_path(&ctx_ptr, op, prop_data_path.c_str(), &ddr->ptr, &ddr->prop)) {
161 MEM_delete(ddr);
162 return false;
163 }
164 }
165 else {
166 /* fallback to the active camera's dof */
167 int index_dummy;
168 uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
169 if (ddr->prop == nullptr) {
171 if (rv3d && rv3d->persp == RV3D_CAMOB) {
172 View3D *v3d = CTX_wm_view3d(C);
173 if (v3d->camera && v3d->camera->data &&
174 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
175 {
176 Camera *camera = (Camera *)v3d->camera->data;
178 &camera->id, &RNA_CameraDOFSettings, &camera->dof);
179 ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance");
180 ddr->is_undo = true;
181 }
182 }
183 }
184 else {
186 }
187 }
188
189 if ((ddr->ptr.data == nullptr) || (ddr->prop == nullptr) ||
190 (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
192 {
193 MEM_delete(ddr);
194 return false;
195 }
196 op->customdata = ddr;
197
200
201 ddr->art = art;
204 ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
205
206 return true;
207}
208
210{
212
213 if (op->customdata) {
215
216 if (ddr->art) {
218 }
219 op->customdata = nullptr;
220 MEM_delete(ddr);
221 }
222}
223
224/* *** depthdropper id helper functions *** */
229 DepthDropper *ddr,
230 const int m_xy[2],
231 float *r_depth)
232{
233 /* we could use some clever */
234 bScreen *screen = CTX_wm_screen(C);
235 ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, m_xy);
236 Scene *scene = CTX_data_scene(C);
237
238 ScrArea *area_prev = CTX_wm_area(C);
239 ARegion *region_prev = CTX_wm_region(C);
240
241 ddr->name[0] = '\0';
242
243 if (area) {
244 if (area->spacetype == SPACE_VIEW3D) {
245 ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, m_xy);
246 if (region) {
248 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
249 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
250 /* weak, we could pass in some reference point */
251 const blender::float3 &view_co = (v3d->camera && rv3d->persp == RV3D_CAMOB) ?
252 v3d->camera->object_to_world().location() :
253 rv3d->viewinv[3];
254
255 const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin};
256 copy_v2_v2_int(ddr->name_pos, mval);
257
258 float co[3];
259
260 CTX_wm_area_set(C, area);
261 CTX_wm_region_set(C, region);
262
263 /* Unfortunately it's necessary to always draw otherwise we leave stale text. */
264 ED_region_tag_redraw(region);
265
267
268 /* Ensure the depth buffer is updated for #ED_view3d_autodist. */
270 depsgraph, region, v3d, nullptr, V3D_DEPTH_NO_GPENCIL, false, nullptr);
271
272 if (ED_view3d_autodist(region, v3d, mval, co, nullptr)) {
273 const float mval_center_fl[2] = {float(region->winx) / 2, float(region->winy) / 2};
274 float co_align[3];
275
276 /* quick way to get view-center aligned point */
277 ED_view3d_win_to_3d(v3d, region, co, mval_center_fl, co_align);
278
279 *r_depth = len_v3v3(view_co, co_align);
280
282 sizeof(ddr->name),
283 double(*r_depth),
284 -4,
286 scene->unit,
287 false);
288 }
289 else {
290 STRNCPY_UTF8(ddr->name, "Nothing under cursor");
291 }
292 }
293 }
294 }
295
296 CTX_wm_area_set(C, area_prev);
297 CTX_wm_region_set(C, region_prev);
298}
299
300/* sets the sample depth RGB, maintaining A */
301static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
302{
303 RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
304 ddr->is_set = true;
305 RNA_property_update(C, &ddr->ptr, ddr->prop);
306}
307
308/* set sample from accumulated values */
310{
311 float depth = ddr->accum_depth;
312 if (ddr->accum_tot) {
313 depth /= float(ddr->accum_tot);
314 }
315 depthdropper_depth_set(C, ddr, depth);
316}
317
318/* single point sample & set */
319static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, const int m_xy[2])
320{
321 float depth = -1.0f;
322 if (depth != -1.0f) {
323 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
324 depthdropper_depth_set(C, ddr, depth);
325 }
326}
327
328static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2])
329{
330 float depth = -1.0f;
331 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
332 if (depth != -1.0f) {
333 ddr->accum_depth += depth;
334 ddr->accum_tot++;
335 }
336}
337
339{
340 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
341 if (ddr->is_set) {
343 }
344 depthdropper_exit(C, op);
345}
346
347/* main modal status check */
349{
350 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
351
352 /* handle modal keymap */
353 if (event->type == EVT_MODAL_MAP) {
354 switch (event->val) {
355 case EYE_MODAL_CANCEL:
357 return OPERATOR_CANCELLED;
359 const bool is_undo = ddr->is_undo;
360 if (ddr->accum_tot == 0) {
361 depthdropper_depth_sample(C, ddr, event->xy);
362 }
363 else {
365 }
366 depthdropper_exit(C, op);
367 /* Could support finished & undo-skip. */
368 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
369 }
371 /* enable accum and make first sample */
372 ddr->accum_start = true;
374 break;
376 ddr->accum_tot = 0;
377 ddr->accum_depth = 0.0f;
380 break;
381 }
382 }
383 else if (event->type == MOUSEMOVE) {
384 if (ddr->accum_start) {
385 /* button is pressed so keep sampling */
388 }
389 }
390
392}
393
394/* Modal Operator init */
396{
397 if (!depthdropper_test(C, op)) {
398 /* If the operator can't be executed, make sure to not consume the event. */
400 }
401 /* init */
402 if (depthdropper_init(C, op)) {
403 wmWindow *win = CTX_wm_window(C);
404 /* Workaround for de-activating the button clearing the cursor, see #76794 */
407
408 /* add temp handler */
410
412 }
413 return OPERATOR_CANCELLED;
414}
415
416/* Repeat operator */
418{
419 /* init */
420 if (depthdropper_init(C, op)) {
421 /* cleanup */
422 depthdropper_exit(C, op);
423
424 return OPERATOR_FINISHED;
425 }
426 return OPERATOR_CANCELLED;
427}
428
430{
432 PropertyRNA *prop;
433 int index_dummy;
434 uiBut *but;
435
436 /* check if there's an active button taking depth value */
437 if ((CTX_wm_window(C) != nullptr) &&
438 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)))
439 {
440 if (but->icon == ICON_EYEDROPPER) {
441 return true;
442 }
443 /* Context menu button. */
444 if (but->optype && STREQ(but->optype->idname, "UI_OT_eyedropper_depth")) {
445 return true;
446 }
447
448 if ((but->type == ButType::Num) && (prop != nullptr) &&
449 (RNA_property_type(prop) == PROP_FLOAT) &&
451 (RNA_property_array_check(prop) == false))
452 {
453 return true;
454 }
455 }
456 else {
458 if (rv3d && rv3d->persp == RV3D_CAMOB) {
459 View3D *v3d = CTX_wm_view3d(C);
460 if (v3d->camera && v3d->camera->data &&
461 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
462 {
463 return true;
464 }
465 }
466 }
467
468 return false;
469}
470
472{
473 /* identifiers */
474 ot->name = "Eyedropper Depth";
475 ot->idname = "UI_OT_eyedropper_depth";
476 ot->description = "Sample depth from the 3D view";
477
478 /* API callbacks. */
479 ot->invoke = depthdropper_invoke;
480 ot->modal = depthdropper_modal;
481 ot->cancel = depthdropper_cancel;
482 ot->exec = depthdropper_exec;
483 ot->poll = depthdropper_poll;
484
485 /* flags */
487
488 /* Paths relative to the context. */
489 PropertyRNA *prop;
490 prop = RNA_def_string(ot->srna,
491 "prop_data_path",
492 nullptr,
493 0,
494 "Data Path",
495 "Path of property to be set with the depth");
497}
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:2523
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
ARegion * BKE_area_find_region_xy(const ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition screen.cc:875
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:257
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:267
@ B_UNIT_LENGTH
Definition BKE_unit.hh:137
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:1882
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 STRNCPY_UTF8(dst, src)
#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:618
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:161
@ PROP_FLOAT
Definition RNA_types.hh:164
@ PROP_UNIT_LENGTH
Definition RNA_types.hh:174
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
@ UI_BUT_UNDO
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)
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
nullptr 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 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)
@ 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)
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)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
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:414
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
ButType type
BIFIconID icon
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int xy[2]
Definition WM_types.hh:761
const char * idname
Definition WM_types.hh:1035
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237