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
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
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. */
272 depsgraph, region, v3d, nullptr, V3D_DEPTH_NO_GPENCIL, false, nullptr);
273
274 if (ED_view3d_autodist(region, v3d, mval, co, nullptr)) {
275 const float mval_center_fl[2] = {float(region->winx) / 2, float(region->winy) / 2};
276 float co_align[3];
277
278 /* quick way to get view-center aligned point */
279 ED_view3d_win_to_3d(v3d, region, co, mval_center_fl, co_align);
280
281 *r_depth = len_v3v3(view_co, co_align);
282
284 sizeof(ddr->name),
285 double(*r_depth),
286 4,
288 &scene->unit,
289 false);
290 }
291 else {
292 STRNCPY(ddr->name, "Nothing under cursor");
293 }
294 }
295 }
296 }
297
298 CTX_wm_area_set(C, area_prev);
299 CTX_wm_region_set(C, region_prev);
300}
301
302/* sets the sample depth RGB, maintaining A */
303static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
304{
305 RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
306 ddr->is_set = true;
307 RNA_property_update(C, &ddr->ptr, ddr->prop);
308}
309
310/* set sample from accumulated values */
312{
313 float depth = ddr->accum_depth;
314 if (ddr->accum_tot) {
315 depth /= float(ddr->accum_tot);
316 }
317 depthdropper_depth_set(C, ddr, depth);
318}
319
320/* single point sample & set */
321static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, const int m_xy[2])
322{
323 float depth = -1.0f;
324 if (depth != -1.0f) {
325 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
326 depthdropper_depth_set(C, ddr, depth);
327 }
328}
329
330static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, const int m_xy[2])
331{
332 float depth = -1.0f;
333 depthdropper_depth_sample_pt(C, ddr, m_xy, &depth);
334 if (depth != -1.0f) {
335 ddr->accum_depth += depth;
336 ddr->accum_tot++;
337 }
338}
339
341{
342 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
343 if (ddr->is_set) {
345 }
346 depthdropper_exit(C, op);
347}
348
349/* main modal status check */
350static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
351{
352 DepthDropper *ddr = static_cast<DepthDropper *>(op->customdata);
353
354 /* handle modal keymap */
355 if (event->type == EVT_MODAL_MAP) {
356 switch (event->val) {
357 case EYE_MODAL_CANCEL:
359 return OPERATOR_CANCELLED;
361 const bool is_undo = ddr->is_undo;
362 if (ddr->accum_tot == 0) {
363 depthdropper_depth_sample(C, ddr, event->xy);
364 }
365 else {
367 }
368 depthdropper_exit(C, op);
369 /* Could support finished & undo-skip. */
370 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
371 }
373 /* enable accum and make first sample */
374 ddr->accum_start = true;
376 break;
378 ddr->accum_tot = 0;
379 ddr->accum_depth = 0.0f;
382 break;
383 }
384 }
385 else if (event->type == MOUSEMOVE) {
386 if (ddr->accum_start) {
387 /* button is pressed so keep sampling */
390 }
391 }
392
394}
395
396/* Modal Operator init */
397static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
398{
399 if (!depthdropper_test(C, op)) {
400 /* If the operator can't be executed, make sure to not consume the event. */
402 }
403 /* init */
404 if (depthdropper_init(C, op)) {
405 wmWindow *win = CTX_wm_window(C);
406 /* Workaround for de-activating the button clearing the cursor, see #76794 */
409
410 /* add temp handler */
412
414 }
415 return OPERATOR_CANCELLED;
416}
417
418/* Repeat operator */
420{
421 /* init */
422 if (depthdropper_init(C, op)) {
423 /* cleanup */
424 depthdropper_exit(C, op);
425
426 return OPERATOR_FINISHED;
427 }
428 return OPERATOR_CANCELLED;
429}
430
432{
434 PropertyRNA *prop;
435 int index_dummy;
436 uiBut *but;
437
438 /* check if there's an active button taking depth value */
439 if ((CTX_wm_window(C) != nullptr) &&
440 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)))
441 {
442 if (but->icon == ICON_EYEDROPPER) {
443 return true;
444 }
445 /* Context menu button. */
446 if (but->optype && STREQ(but->optype->idname, "UI_OT_eyedropper_depth")) {
447 return true;
448 }
449
450 if ((but->type == UI_BTYPE_NUM) && (prop != nullptr) &&
451 (RNA_property_type(prop) == PROP_FLOAT) &&
453 (RNA_property_array_check(prop) == false))
454 {
455 return true;
456 }
457 }
458 else {
460 if (rv3d && rv3d->persp == RV3D_CAMOB) {
461 View3D *v3d = CTX_wm_view3d(C);
462 if (v3d->camera && v3d->camera->data &&
463 BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(v3d->camera->data)))
464 {
465 return true;
466 }
467 }
468 }
469
470 return false;
471}
472
474{
475 /* identifiers */
476 ot->name = "Eyedropper Depth";
477 ot->idname = "UI_OT_eyedropper_depth";
478 ot->description = "Sample depth from the 3D view";
479
480 /* api callbacks */
481 ot->invoke = depthdropper_invoke;
482 ot->modal = depthdropper_modal;
483 ot->cancel = depthdropper_cancel;
484 ot->exec = depthdropper_exec;
485 ot->poll = depthdropper_poll;
486
487 /* flags */
489
490 /* Paths relative to the context. */
491 PropertyRNA *prop;
492 prop = RNA_def_string(ot->srna,
493 "prop_data_path",
494 nullptr,
495 0,
496 "Data Path",
497 "Path of property to be set with the depth");
499}
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_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])
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)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
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
#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)
@ UI_BTYPE_NUM
bool UI_but_flag_is_set(uiBut *but, int flag)
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
BPy_StructRNA * 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)
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
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
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(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
void * regiondata
PropertyRNA * prop
ARegionType * art
Definition DNA_ID.h:413
void * first
void * data
Definition RNA_types.hh:42
float viewinv[4][4]
struct UnitSettings unit
ListBase spacedata
struct Object * camera
int ymin
int xmin
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 * idname
Definition WM_types.hh:992
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