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_scene.hh"
29#include "BKE_screen.hh"
30#include "BKE_unit.hh"
31
32#include "RNA_access.hh"
33#include "RNA_define.hh"
34#include "RNA_path.hh"
35#include "RNA_prototypes.hh"
36
37#include "UI_interface.hh"
38
39#include "WM_api.hh"
40#include "WM_types.hh"
41
42#include "ED_screen.hh"
43#include "ED_space_api.hh"
44#include "ED_view3d.hh"
45
46#include "eyedropper_intern.hh"
47#include "interface_intern.hh"
48
49#include "ANIM_keyframing.hh"
50
56 PropertyRNA *prop = nullptr;
57 bool is_undo = false;
58
59 bool is_set = false;
60 float init_depth = 0.0f; /* For resetting on cancel. */
61
62 bool accum_start = false; /* Has mouse been pressed. */
63 float accum_depth = 0.0f;
64 int accum_tot = 0;
65
66 ARegionType *art = nullptr;
67 void *draw_handle_pixel = nullptr;
68 int name_pos[2] = {};
69 char name[200] = {};
70};
71
72static void depthdropper_draw_cb(const bContext * /*C*/, ARegion * /*region*/, void *arg)
73{
74 DepthDropper *ddr = static_cast<DepthDropper *>(arg);
76}
77
78static bool depthdropper_get_path(PointerRNA *ctx_ptr,
79 wmOperator *op,
80 const char *prop_path,
81 PointerRNA *r_ptr,
82 PropertyRNA **r_prop)
83{
84 PropertyRNA *unused_prop;
85
86 if (prop_path[0] == '\0') {
87 return false;
88 }
89
90 if (!r_prop) {
91 r_prop = &unused_prop;
92 }
93
94 /* Get rna from path. */
95 if (!RNA_path_resolve(ctx_ptr, prop_path, r_ptr, r_prop)) {
96 BKE_reportf(op->reports, RPT_ERROR, "Could not resolve path '%s'", prop_path);
97 return false;
98 }
99
100 /* Check property type. */
101 PropertyType prop_type = RNA_property_type(*r_prop);
102 if (prop_type != PROP_FLOAT) {
103 BKE_reportf(op->reports, RPT_ERROR, "Property from path '%s' is not a float", prop_path);
104 return false;
105 }
106
107 /* Success. */
108 return true;
109}
110
112{
114 PropertyRNA *prop;
115 int index_dummy;
116 uiBut *but;
117
118 /* Check if the custom prop_data_path is set. */
119 if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) &&
120 RNA_property_is_set(op->ptr, prop))
121 {
122 return true;
123 }
124
125 /* check if there's an active button taking depth value */
126 if ((CTX_wm_window(C) != nullptr) &&
127 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
128 (but->type == UI_BTYPE_NUM) && (prop != nullptr))
129 {
130 if ((RNA_property_type(prop) == PROP_FLOAT) &&
132 (RNA_property_array_check(prop) == false))
133 {
134 return true;
135 }
136 }
137 else {
139 if (rv3d && rv3d->persp == RV3D_CAMOB) {
140 View3D *v3d = CTX_wm_view3d(C);
141 if (v3d->camera && v3d->camera->data &&
142 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
143 {
144 return true;
145 }
146 }
147 }
148
149 return false;
150}
151
153{
154 DepthDropper *ddr = MEM_new<DepthDropper>(__func__);
155 PropertyRNA *prop;
156 if ((prop = RNA_struct_find_property(op->ptr, "prop_data_path")) &&
157 RNA_property_is_set(op->ptr, prop))
158 {
159 char *prop_data_path = RNA_string_get_alloc(op->ptr, "prop_data_path", nullptr, 0, nullptr);
160 BLI_SCOPED_DEFER([&] { MEM_SAFE_FREE(prop_data_path); });
161 if (!prop_data_path) {
162 MEM_delete(ddr);
163 return false;
164 }
165 PointerRNA ctx_ptr = RNA_pointer_create_discrete(nullptr, &RNA_Context, C);
166 if (!depthdropper_get_path(&ctx_ptr, op, prop_data_path, &ddr->ptr, &ddr->prop)) {
167 MEM_delete(ddr);
168 return false;
169 }
170 }
171 else {
172 /* fallback to the active camera's dof */
173 int index_dummy;
174 uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
175 if (ddr->prop == nullptr) {
177 if (rv3d && rv3d->persp == RV3D_CAMOB) {
178 View3D *v3d = CTX_wm_view3d(C);
179 if (v3d->camera && v3d->camera->data &&
180 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
181 {
182 Camera *camera = (Camera *)v3d->camera->data;
184 &camera->id, &RNA_CameraDOFSettings, &camera->dof);
185 ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance");
186 ddr->is_undo = true;
187 }
188 }
189 }
190 else {
192 }
193 }
194
195 if ((ddr->ptr.data == nullptr) || (ddr->prop == nullptr) ||
196 (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
198 {
199 MEM_delete(ddr);
200 return false;
201 }
202 op->customdata = ddr;
203
206
207 ddr->art = art;
210 ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
211
212 return true;
213}
214
216{
218
219 if (op->customdata) {
221
222 if (ddr->art) {
224 }
225 op->customdata = nullptr;
226 MEM_delete(ddr);
227 }
228}
229
230/* *** depthdropper id helper functions *** */
235 DepthDropper *ddr,
236 const int m_xy[2],
237 float *r_depth)
238{
239 /* we could use some clever */
240 bScreen *screen = CTX_wm_screen(C);
241 ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, m_xy);
242 Scene *scene = CTX_data_scene(C);
243
244 ScrArea *area_prev = CTX_wm_area(C);
245 ARegion *region_prev = CTX_wm_region(C);
246
247 ddr->name[0] = '\0';
248
249 if (area) {
250 if (area->spacetype == SPACE_VIEW3D) {
251 ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, m_xy);
252 if (region) {
254 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
255 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
256 /* weak, we could pass in some reference point */
257 const blender::float3 &view_co = (v3d->camera && rv3d->persp == RV3D_CAMOB) ?
258 v3d->camera->object_to_world().location() :
259 rv3d->viewinv[3];
260
261 const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin};
262 copy_v2_v2_int(ddr->name_pos, mval);
263
264 float co[3];
265
266 CTX_wm_area_set(C, area);
267 CTX_wm_region_set(C, region);
268
269 /* Unfortunately it's necessary to always draw otherwise we leave stale text. */
270 ED_region_tag_redraw(region);
271
273
274 /* Ensure the depth buffer is updated for #ED_view3d_autodist. */
276 depsgraph, region, v3d, nullptr, V3D_DEPTH_NO_GPENCIL, false, nullptr);
277
278 if (ED_view3d_autodist(region, v3d, mval, co, nullptr)) {
279 const float mval_center_fl[2] = {float(region->winx) / 2, float(region->winy) / 2};
280 float co_align[3];
281
282 /* quick way to get view-center aligned point */
283 ED_view3d_win_to_3d(v3d, region, co, mval_center_fl, co_align);
284
285 *r_depth = len_v3v3(view_co, co_align);
286
288 sizeof(ddr->name),
289 double(*r_depth),
290 4,
292 scene->unit,
293 false);
294 }
295 else {
296 STRNCPY(ddr->name, "Nothing under cursor");
297 }
298 }
299 }
300 }
301
302 CTX_wm_area_set(C, area_prev);
303 CTX_wm_region_set(C, region_prev);
304}
305
306/* sets the sample depth RGB, maintaining A */
307static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
308{
309 RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
310 ddr->is_set = true;
311 RNA_property_update(C, &ddr->ptr, ddr->prop);
312 Scene *scene = CTX_data_scene(C);
313 const bool only_when_keyed = blender::animrig::is_keying_flag(scene,
316 C, scene, &ddr->ptr, ddr->prop, 0, BKE_scene_frame_get(scene), only_when_keyed);
317}
318
319/* set sample from accumulated values */
321{
322 float depth = ddr->accum_depth;
323 if (ddr->accum_tot) {
324 depth /= float(ddr->accum_tot);
325 }
326 depthdropper_depth_set(C, ddr, depth);
327}
328
329/* single point sample & set */
330static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, const int m_xy[2])
331{
332 float depth = -1.0f;
333 if (depth != -1.0f) {
334 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
335 depthdropper_depth_set(C, ddr, depth);
336 }
337}
338
339static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2])
340{
341 float depth = -1.0f;
342 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
343 if (depth != -1.0f) {
344 ddr->accum_depth += depth;
345 ddr->accum_tot++;
346 }
347}
348
350{
351 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
352 if (ddr->is_set) {
354 }
355 depthdropper_exit(C, op);
356}
357
358/* main modal status check */
360{
361 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
362
363 /* handle modal keymap */
364 if (event->type == EVT_MODAL_MAP) {
365 switch (event->val) {
366 case EYE_MODAL_CANCEL:
368 return OPERATOR_CANCELLED;
370 const bool is_undo = ddr->is_undo;
371 if (ddr->accum_tot == 0) {
372 depthdropper_depth_sample(C, ddr, event->xy);
373 }
374 else {
376 }
377 depthdropper_exit(C, op);
378 /* Could support finished & undo-skip. */
379 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
380 }
382 /* enable accum and make first sample */
383 ddr->accum_start = true;
385 break;
387 ddr->accum_tot = 0;
388 ddr->accum_depth = 0.0f;
391 break;
392 }
393 }
394 else if (event->type == MOUSEMOVE) {
395 if (ddr->accum_start) {
396 /* button is pressed so keep sampling */
399 }
400 }
401
403}
404
405/* Modal Operator init */
407{
408 if (!depthdropper_test(C, op)) {
409 /* If the operator can't be executed, make sure to not consume the event. */
411 }
412 /* init */
413 if (depthdropper_init(C, op)) {
414 wmWindow *win = CTX_wm_window(C);
415 /* Workaround for de-activating the button clearing the cursor, see #76794 */
418
419 /* add temp handler */
421
423 }
424 return OPERATOR_CANCELLED;
425}
426
427/* Repeat operator */
429{
430 /* init */
431 if (depthdropper_init(C, op)) {
432 /* cleanup */
433 depthdropper_exit(C, op);
434
435 return OPERATOR_FINISHED;
436 }
437 return OPERATOR_CANCELLED;
438}
439
441{
443 PropertyRNA *prop;
444 int index_dummy;
445 uiBut *but;
446
447 /* check if there's an active button taking depth value */
448 if ((CTX_wm_window(C) != nullptr) &&
449 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)))
450 {
451 if (but->icon == ICON_EYEDROPPER) {
452 return true;
453 }
454 /* Context menu button. */
455 if (but->optype && STREQ(but->optype->idname, "UI_OT_eyedropper_depth")) {
456 return true;
457 }
458
459 if ((but->type == UI_BTYPE_NUM) && (prop != nullptr) &&
460 (RNA_property_type(prop) == PROP_FLOAT) &&
462 (RNA_property_array_check(prop) == false))
463 {
464 return true;
465 }
466 }
467 else {
469 if (rv3d && rv3d->persp == RV3D_CAMOB) {
470 View3D *v3d = CTX_wm_view3d(C);
471 if (v3d->camera && v3d->camera->data &&
472 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
473 {
474 return true;
475 }
476 }
477 }
478
479 return false;
480}
481
483{
484 /* identifiers */
485 ot->name = "Eyedropper Depth";
486 ot->idname = "UI_OT_eyedropper_depth";
487 ot->description = "Sample depth from the 3D view";
488
489 /* API callbacks. */
490 ot->invoke = depthdropper_invoke;
491 ot->modal = depthdropper_modal;
492 ot->cancel = depthdropper_cancel;
493 ot->exec = depthdropper_exec;
494 ot->poll = depthdropper_poll;
495
496 /* flags */
498
499 /* Paths relative to the context. */
500 PropertyRNA *prop;
501 prop = RNA_def_string(ot->srna,
502 "prop_data_path",
503 nullptr,
504 0,
505 "Data Path",
506 "Path of property to be set with the depth");
508}
Functions to insert, delete or modify keyframes.
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
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2381
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
@ AUTOKEY_FLAG_INSERTAVAILABLE
@ 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)
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
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:4227
wmOperatorType * ot
Definition wm_files.cc:4226