Blender V5.0
view3d_gizmo_ruler.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_listbase.h"
10#include "BLI_math_geom.h"
11#include "BLI_math_matrix.hh"
13#include "BLI_math_rotation.h"
15#include "BLI_string_utf8.h"
16#include "BLI_utildefines.h"
17
18#include "BKE_context.hh"
19#include "BKE_gpencil_legacy.h"
20#include "BKE_layer.hh"
21#include "BKE_report.hh"
22#include "BKE_scene.hh"
23#include "BKE_screen.hh"
24#include "BKE_unit.hh"
25
27#include "DNA_object_types.h"
28#include "DNA_view3d_types.h"
29
30#include "ED_gizmo_library.hh"
31#include "ED_gizmo_utils.hh"
32#include "ED_screen.hh"
33#include "ED_transform.hh"
35#include "ED_view3d.hh"
36
37#include "UI_interface.hh"
38#include "UI_resources.hh"
39
40#include "MEM_guardedalloc.h"
41
42#include "RNA_access.hh"
43
44#include "WM_api.hh"
45#include "WM_toolsystem.hh"
46#include "WM_types.hh"
47
49
50#include "view3d_intern.hh" /* own include */
51
52#include "GPU_immediate.hh"
53#include "GPU_immediate_util.hh"
54#include "GPU_matrix.hh"
55#include "GPU_state.hh"
56
57#include "BLF_api.hh"
58
59using blender::float2;
61using blender::float3;
64using blender::float4;
65
70#define USE_AXIS_CONSTRAINTS
71
72static const char *view3d_gzgt_ruler_id = "VIEW3D_GGT_ruler";
73
74#define MVAL_MAX_PX_DIST 12.0f
75
76/* -------------------------------------------------------------------- */
77/* Ruler Item (we can have many) */
78
79enum {
84};
85
86/* keep smaller than selection, since we may want click elsewhere without selecting a ruler */
87#define RULER_PICK_DIST 12.0f
88#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST)
89
90/* not clicking on a point */
91#define PART_LINE 0xff
92
93/* -------------------------------------------------------------------- */
94/* Ruler Info (wmGizmoGroup customdata) */
95
96enum {
99};
100
101#ifdef USE_AXIS_CONSTRAINTS
102/* Constrain axes */
103enum {
108};
109
114enum {
118};
119#endif /* USE_AXIS_CONSTRAINTS */
120
121struct RulerItem;
122
123struct RulerInfo {
125 int flag;
127 int state;
128
129#ifdef USE_AXIS_CONSTRAINTS
131#endif
132
133 /* wm state */
137 ARegion *region; /* re-assigned every modal update */
138
139 /* Track changes in state. */
140 struct {
141#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
142 bool do_snap;
143#endif
146
147 struct {
152};
153
154/* -------------------------------------------------------------------- */
155/* Ruler Item (two or three points) */
156
157struct RulerItem {
159
163
164 int flag;
165 int raycast_dir; /* RULER_DIRECTION_* */
166};
167
169 /* selected coord */
170 char co_index; /* 0 -> 2 */
172};
173
174/* -------------------------------------------------------------------- */
177
179{
180 /* could pass this as an arg */
181 const wmGizmoType *gzt_ruler = WM_gizmotype_find("VIEW3D_GT_ruler_item", true);
182 RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, nullptr);
183 WM_gizmo_set_flag(&ruler_item->gz, WM_GIZMO_DRAW_MODAL, true);
184 return ruler_item;
185}
186
187static void ruler_item_remove(bContext *C, wmGizmoGroup *gzgroup, RulerItem *ruler_item)
188{
189 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
190 if (ruler_info->item_active == ruler_item) {
191 ruler_info->item_active = nullptr;
192 }
193 WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, &ruler_item->gz, C);
194}
195
197 RulerItem *ruler_item, const UnitSettings &unit, char *numstr, size_t numstr_size, int prec)
198{
199 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
200 const float ruler_angle = angle_v3v3v3(
201 ruler_item->co[0], ruler_item->co[1], ruler_item->co[2]);
202
203 if (unit.system == USER_UNIT_NONE) {
205 numstr, numstr_size, "%.*f" BLI_STR_UTF8_DEGREE_SIGN, prec, RAD2DEGF(ruler_angle));
206 }
207 else {
209 numstr, numstr_size, double(ruler_angle), prec, B_UNIT_ROTATION, unit, false);
210 }
211 }
212 else {
213 const float ruler_len = len_v3v3(ruler_item->co[0], ruler_item->co[2]);
214
215 if (unit.system == USER_UNIT_NONE) {
216 BLI_snprintf_utf8(numstr, numstr_size, "%.*f", prec, ruler_len);
217 }
218 else {
220 numstr, numstr_size, ruler_len, prec, B_UNIT_LENGTH, unit, false);
221 }
222 }
223}
224
225static bool view3d_ruler_pick(wmGizmoGroup *gzgroup,
226 RulerItem *ruler_item,
227 const float2 mval,
228 int *r_co_index)
229{
230 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
231 ARegion *region = ruler_info->region;
232 bool found = false;
233
234 float dist_best = RULER_PICK_DIST_SQ;
235 int co_index_best = -1;
236
237 {
238 float3x2 co_ss;
239 float dist;
240 int j;
241
242 /* should these be checked? - ok for now not to */
243 for (j = 0; j < 3; j++) {
244 ED_view3d_project_float_global(region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
245 }
246
247 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
248 dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]),
249 dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2]));
250 if (dist < dist_best) {
251 dist_best = dist;
252 found = true;
253
254 {
255 const float3 dist_points = {
256 blender::math::distance_squared(co_ss[0], mval),
257 blender::math::distance_squared(co_ss[1], mval),
258 blender::math::distance_squared(co_ss[2], mval),
259 };
260 if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) {
261 co_index_best = min_axis_v3(dist_points);
262 }
263 else {
264 co_index_best = -1;
265 }
266 }
267 }
268 }
269 else {
270 dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]);
271 if (dist < dist_best) {
272 dist_best = dist;
273 found = true;
274
275 {
276 const float2 dist_points = {
277 blender::math::distance_squared(co_ss[0], mval),
278 blender::math::distance_squared(co_ss[2], mval),
279 };
280 if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) {
281 co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2;
282 }
283 else {
284 co_index_best = -1;
285 }
286 }
287 }
288 }
289 }
290 UNUSED_VARS(dist_best);
291
292 *r_co_index = co_index_best;
293 return found;
294}
295
300static void ruler_state_set(RulerInfo *ruler_info, int state)
301{
302 if (state == ruler_info->state) {
303 return;
304 }
305
306 if (state == RULER_STATE_NORMAL) {
309 ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, nullptr);
310 }
311 else if (state == RULER_STATE_DRAG) {
312 memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev));
313
314 /* Force the snap cursor to appear even though it is not highlighted. */
316 }
317 else {
318 BLI_assert(0);
319 }
320
321 ruler_info->state = state;
322}
323
324static void view3d_ruler_item_project(RulerInfo *ruler_info, float3 &r_co, const int xy[2])
325{
326 ED_view3d_win_to_3d_int(static_cast<const View3D *>(ruler_info->area->spacedata.first),
327 ruler_info->region,
328 r_co,
329 xy,
330 r_co);
331}
332
337 Depsgraph *depsgraph,
338 RulerInfo *ruler_info,
339 RulerItem *ruler_item,
340 const int mval[2],
341 const bool do_thickness,
342 const bool do_snap)
343{
344 wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo;
345 constexpr float eps_bias = 0.0002f;
346 float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
347
348 if (ruler_item) {
349 RulerInteraction *inter = static_cast<RulerInteraction *>(ruler_item->gz.interaction_data);
350 float3 &co = ruler_item->co[inter->co_index];
351 eSnapMode *snap_source_type = &ruler_item->snap_type[inter->co_index];
352 /* restore the initial depth */
353 co = inter->drag_start_co;
354 view3d_ruler_item_project(ruler_info, co, mval);
355 if (do_thickness && inter->co_index != 1) {
357 View3D *v3d = static_cast<View3D *>(ruler_info->area->spacedata.first);
359 ED_gizmotypes_snap_3d_context_ensure(scene, snap_gizmo);
360 const float2 mval_fl = {float(mval[0]), float(mval[1])};
361 float3 ray_normal;
362 float3 ray_start;
363 float3 &co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0];
364
365 blender::ed::transform::SnapObjectParams snap_object_params{};
366 snap_object_params.snap_target_select = SCE_SNAP_TARGET_ALL;
368
370 depsgraph,
371 ruler_info->region,
372 v3d,
374 &snap_object_params,
375 nullptr,
376 mval_fl,
377 nullptr,
378 &dist_px,
379 co,
380 ray_normal);
381 if (hit) {
382 /* add some bias */
383 ray_start = co - ray_normal * eps_bias;
385 depsgraph,
386 v3d,
387 &snap_object_params,
388 ray_start,
389 -ray_normal,
390 nullptr,
391 co_other,
392 nullptr);
393 }
394 }
395 else {
396 View3D *v3d = static_cast<View3D *>(ruler_info->area->spacedata.first);
397 if (do_snap) {
398 float3 *prev_point = nullptr;
399 eSnapMode snap_type;
401
402 if (inter->co_index != 1) {
403 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
404 prev_point = &ruler_item->co[1];
405 snap_type = ruler_item->snap_type[1];
406 }
407 else if (inter->co_index == 0) {
408 prev_point = &ruler_item->co[2];
409 snap_type = ruler_item->snap_type[2];
410 }
411 else {
412 prev_point = &ruler_item->co[0];
413 snap_type = ruler_item->snap_type[0];
414 }
415 }
416 if (prev_point != nullptr) {
418 snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point);
420 snap_gizmo->ptr, ruler_info->snap_data.prop_snap_source_type, snap_type);
421 }
422
423 ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, nullptr, nullptr, snap_source_type);
424 }
425
426#ifdef USE_AXIS_CONSTRAINTS
427 if (!(ruler_item->flag & RULERITEM_USE_ANGLE) &&
428 ruler_info->constrain_mode != CONSTRAIN_MODE_OFF)
429 {
430
433 RegionView3D *rv3d = static_cast<RegionView3D *>(ruler_info->region->regiondata);
434 BKE_view_layer_synced_ensure(scene, view_layer);
436 Object *obedit = OBEDIT_FROM_OBACT(ob);
437
438 short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
439
440 if (ruler_info->constrain_mode == CONSTRAIN_MODE_2) {
441 orient_index = (orient_index == V3D_ORIENT_GLOBAL) ? V3D_ORIENT_LOCAL :
443 }
444
445 const int pivot_point = scene->toolsettings->transform_pivot_point;
446 float3x3 mat;
447
449 scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat.ptr());
450
451 ruler_item->co = blender::math::invert(mat) * ruler_item->co;
452
453 /* Loop through the axes and constrain the dragged point to the current constrained axis.
454 */
455 for (int i = 0; i <= 2; i++) {
456 if (ruler_info->constrain_axis != i) {
457 ruler_item->co[inter->co_index][i] = ruler_item->co[(inter->co_index == 0) ? 2 : 0][i];
458 }
459 }
460 ruler_item->co = mat * ruler_item->co;
461 }
462#endif
463 }
464 return true;
465 }
466 return false;
467}
468
478{
479 return gzgroup->customdata != nullptr;
480}
481
483
484/* -------------------------------------------------------------------- */
487
488/* Helper: Find the layer created as ruler. */
490{
491 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
492 if (gpl->flag & GP_LAYER_IS_RULER) {
493 return gpl;
494 }
495 }
496 return nullptr;
497}
498
500{
501#ifndef NDEBUG
502 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
503 BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo);
504#endif
505 return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next;
506}
507
508#define RULER_ID "RulerData3D"
509
510/* GP data creation has to happen before the undo step is stored.
511 * See also #116734. */
513{
514 // RulerInfo *ruler_info = gzgroup->customdata;
515 Main *bmain = CTX_data_main(C);
516 Scene *scene = CTX_data_scene(C);
517 if (scene->gpd == nullptr) {
518 scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
521 }
522}
523
525{
526 // RulerInfo *ruler_info = gzgroup->customdata;
527 Scene *scene = CTX_data_scene(C);
528
529 bGPdata *gpd;
530 bGPDlayer *gpl;
531 bGPDframe *gpf;
532 bGPDstroke *gps;
533 RulerItem *ruler_item;
534 const char *ruler_name = RULER_ID;
535 bool changed = false;
536
537 BLI_assert(scene->gpd != nullptr);
538 gpd = scene->gpd;
539
540 gpl = view3d_ruler_layer_get(gpd);
541 if (gpl == nullptr) {
542 gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false, false);
543 copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
544 gpl->thickness = 1;
546 }
547
550
551 for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item;
552 ruler_item = (RulerItem *)ruler_item->gz.next)
553 {
554 bGPDspoint *pt;
555 int j;
556
557 /* allocate memory for a new stroke */
558 gps = MEM_callocN<bGPDstroke>("gp_stroke");
559 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
560 gps->totpoints = 3;
561 pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints,
562 "gp_stroke_points");
563 for (j = 0; j < 3; j++) {
564 copy_v3_v3(&pt->x, ruler_item->co[j]);
565 pt->pressure = 1.0f;
566 pt->strength = 1.0f;
567 pt++;
568 }
569 }
570 else {
571 gps->totpoints = 2;
572 pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints,
573 "gp_stroke_points");
574 for (j = 0; j < 3; j += 2) {
575 copy_v3_v3(&pt->x, ruler_item->co[j]);
576 pt->pressure = 1.0f;
577 pt->strength = 1.0f;
578 pt++;
579 }
580 }
581 gps->flag = GP_STROKE_3DSPACE;
582 gps->thickness = 3;
583 gps->hardness = 1.0f;
584 gps->fill_opacity_fac = 1.0f;
585 copy_v2_fl(gps->aspect_ratio, 1.0f);
586 gps->uv_scale = 1.0f;
587
588 BLI_addtail(&gpf->strokes, gps);
589 changed = true;
590 }
591
592 return changed;
593}
594
596{
597 Scene *scene = CTX_data_scene(C);
598 bool changed = false;
599
600 if (scene->gpd) {
601 bGPDlayer *gpl;
602 gpl = view3d_ruler_layer_get(scene->gpd);
603 if (gpl) {
604 bGPDframe *gpf;
606 if (gpf) {
607 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
608 bGPDspoint *pt = gps->points;
609 int j;
610 RulerItem *ruler_item = nullptr;
611 if (gps->totpoints == 3) {
612 ruler_item = ruler_item_add(gzgroup);
613 for (j = 0; j < 3; j++) {
614 copy_v3_v3(ruler_item->co[j], &pt->x);
615 pt++;
616 }
617 ruler_item->flag |= RULERITEM_USE_ANGLE;
618 changed = true;
619 }
620 else if (gps->totpoints == 2) {
621 ruler_item = ruler_item_add(gzgroup);
622 for (j = 0; j < 3; j += 2) {
623 copy_v3_v3(ruler_item->co[j], &pt->x);
624 pt++;
625 }
626 changed = true;
627 }
628 }
629 }
630 }
631 }
632
633 return changed;
634}
635
637{
639 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
640 const Scene *scene = WM_window_get_active_scene(win);
641 if (!scene->gpd) {
642 continue;
643 }
644
645 bGPDlayer *gpl_scene = view3d_ruler_layer_get(scene->gpd);
646 if (gpl_scene != gpl) {
647 continue;
648 }
649
650 const bScreen *screen = WM_window_get_active_screen(win);
651 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
652 if (area->spacetype != SPACE_VIEW3D) {
653 continue;
654 }
655
657 if (!region) {
658 continue;
659 }
660
661 wmGizmoMap *gzmap = region->runtime->gizmo_map;
663
664 if (!gzgroup) {
665 continue;
666 }
667 RulerItem *ruler_item;
668 while ((ruler_item = gzgroup_ruler_item_first_get(gzgroup))) {
669 ruler_item_remove(C, gzgroup, ruler_item);
670 }
671
673 }
674 }
675}
676
678
679/* -------------------------------------------------------------------- */
682
683static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
684{
685 Scene *scene = CTX_data_scene(C);
686 const UnitSettings &unit = scene->unit;
687 RulerInfo *ruler_info = static_cast<RulerInfo *>(gz->parent_gzgroup->customdata);
688 RulerItem *ruler_item = (RulerItem *)gz;
689 ARegion *region = ruler_info->region;
690 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
691 const float cap_size = 4.0f * UI_SCALE_FAC;
692 const float bg_margin = 4.0f * UI_SCALE_FAC;
693 const float arc_size = 64.0f * UI_SCALE_FAC;
694 constexpr int arc_steps = 24;
695 const float4 color_act = {1.0f, 1.0f, 1.0f, 1.0f};
696 const float4 color_base = {0.0f, 0.0f, 0.0f, 1.0f};
697 uchar color_text[3];
698 uchar color_wire[3];
699 float4 color_back = {1.0f, 1.0f, 1.0f, 0.5f};
700
701 /* Pixel Space. */
706
707 /* anti-aliased lines for more consistent appearance */
708 GPU_line_smooth(true);
709 GPU_line_width(1.0f);
710
714
715 UI_GetThemeColor3ubv(TH_TEXT, color_text);
716 UI_GetThemeColor3ubv(TH_WIRE, color_wire);
717
718 /* Avoid white on white text. (TODO: Fix by using theme). */
719 if (int(color_text[0]) + int(color_text[1]) + int(color_text[2]) > 127 * 3 * 0.6f) {
720 copy_v3_fl(color_back, 0.0f);
721 }
722
723 const bool is_act = (ruler_info->item_active == ruler_item);
724 float2 dir_ruler;
725 float3x2 co_ss;
726 bool proj_ok[3];
727 int j;
728
729 /* Check if each corner is behind the near plane. If it is, we do not draw certain lines. */
730 for (j = 0; j < 3; j++) {
732 region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_CLIP_NEAR);
733 proj_ok[j] = (status == V3D_PROJ_RET_OK);
734 }
735
736 /* 3d drawing. */
737
741 GPU_matrix_set(rv3d->viewmat);
742
744
745 const uint shdr_pos_3d = GPU_vertformat_attr_add(
746 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
747
748 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
750
751 float4 viewport_size(0.0f);
752 GPU_viewport_size_get_f(viewport_size);
753 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
754
755 immUniform1i("colors_len", 2); /* "advanced" mode */
756 const float4 &col = is_act ? color_act : color_base;
757 immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f);
758 immUniform4fv("color2", col);
759 immUniform1f("dash_width", 6.0f);
760 immUniform1f("udash_factor", 0.5f);
761
763
764 immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
765 immVertex3fv(shdr_pos_3d, ruler_item->co[1]);
766 immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
767
768 immEnd();
769
771
773
774 /* arc */
775 {
776 float3 dir_tmp;
777 float3 ar_coord;
778
779 float3 dir_a;
780 float3 dir_b;
781 float4 quat;
782 float3 axis;
783 float angle;
784 const float px_scale = (ED_view3d_pixel_size_no_ui_scale(rv3d, ruler_item->co[1]) *
785 min_fff(arc_size,
786 blender::math::distance(co_ss[0], co_ss[1]) / 2.0f,
787 blender::math::distance(co_ss[2], co_ss[1]) / 2.0f));
788
789 dir_a = blender::math::normalize(ruler_item->co[0] - ruler_item->co[1]);
790 dir_b = blender::math::normalize(ruler_item->co[2] - ruler_item->co[1]);
791 axis = blender::math::cross(dir_a, dir_b);
792 angle = angle_normalized_v3v3(dir_a, dir_b);
793
794 axis_angle_to_quat(quat, axis, angle / arc_steps);
795
796 dir_tmp = dir_a;
797
798 immUniformColor3ubv(color_wire);
799
800 immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1);
801
802 for (j = 0; j <= arc_steps; j++) {
803 ar_coord = ruler_item->co[1] + dir_tmp * px_scale;
804 mul_qt_v3(quat, dir_tmp);
805
806 immVertex3fv(shdr_pos_3d, ar_coord);
807 }
808
809 immEnd();
810 }
811
813 }
814 else {
816
817 float viewport_size[4];
818 GPU_viewport_size_get_f(viewport_size);
819 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
820
821 immUniform1i("colors_len", 2); /* "advanced" mode */
822 const float *col = is_act ? color_act : color_base;
823 immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f);
824 immUniform4fv("color2", col);
825 immUniform1f("dash_width", 6.0f);
826 immUniform1f("udash_factor", 0.5f);
827
829
830 immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
831 immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
832
833 immEnd();
834
836 }
837
838 /* 2d drawing. */
839
842
843 const uint shdr_pos_2d = GPU_vertformat_attr_add(
844 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
845
846 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
848 /* capping */
849 {
850 float2 cap;
851
852 dir_ruler = co_ss[0] - co_ss[1];
853 float2 rot_90_vec_a = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]});
854
855 dir_ruler = co_ss[1] - co_ss[2];
856 float2 rot_90_vec_b = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]});
857
859
860 if (proj_ok[1] && is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
861 GPU_line_width(3.0f);
862 immUniformColor3fv(color_act);
864 /* angle vertex */
865 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
866 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
867 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
868 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
869
870 immEnd();
871 GPU_line_width(1.0f);
872 }
873
874 immUniformColor3ubv(color_wire);
875
876 if (proj_ok[0] || proj_ok[2] || proj_ok[1]) {
877 immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4);
878
879 if (proj_ok[0]) {
880 cap = co_ss[0] + rot_90_vec_a * cap_size;
881 immVertex2fv(shdr_pos_2d, cap);
882 cap = co_ss[0] - rot_90_vec_a * cap_size;
883 immVertex2fv(shdr_pos_2d, cap);
884 }
885
886 if (proj_ok[2]) {
887 cap = co_ss[2] + rot_90_vec_b * cap_size;
888 immVertex2fv(shdr_pos_2d, cap);
889 cap = co_ss[2] - rot_90_vec_b * cap_size;
890 immVertex2fv(shdr_pos_2d, cap);
891 }
892
893 /* angle vertex */
894 if (proj_ok[1]) {
895 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
896 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
897 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
898 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
899 }
900
901 immEnd();
902 }
903
905 }
906
907 /* text */
908 char numstr[256];
909 float2 numstr_size;
910 float posit[2];
911 const int prec = 2; /* XXX, todo, make optional */
912
913 ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
914
915 BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
916
917 /* Center text. */
918 posit[0] = co_ss[1][0] - (numstr_size[0] / 2.0f);
919 posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
920
921 /* Adjust text position to help readability. */
922 sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
923 float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
924 normalize_v2(rot_90_vec);
925 posit[1] += rot_90_vec[0] * numstr_size[1];
926 posit[0] += (rot_90_vec[1] < 0) ? numstr_size[0] : -numstr_size[0];
927
928 /* draw text (bg) */
929 if (proj_ok[1]) {
930 immUniformColor4fv(color_back);
932 immRectf(shdr_pos_2d,
933 posit[0] - bg_margin,
934 posit[1] - bg_margin,
935 posit[0] + bg_margin + numstr_size[0],
936 posit[1] + bg_margin + numstr_size[1]);
938 }
939
941
942 /* draw text */
943 if (proj_ok[1]) {
944 BLF_color3ubv(blf_mono_font, color_text);
945 BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
947 BLF_draw(blf_mono_font, numstr, sizeof(numstr));
948 }
949 }
950 else {
952
953 dir_ruler = co_ss[0] - co_ss[2];
954 float2 rot_90_vec = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]});
955
956 /* capping */
957 {
958 float2 cap;
959
961
962 immUniformColor3ubv(color_wire);
963
964 if (proj_ok[0] || proj_ok[2]) {
965 immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2);
966
967 if (proj_ok[0]) {
968 cap = co_ss[0] + rot_90_vec * cap_size;
969 immVertex2fv(shdr_pos_2d, cap);
970 cap = co_ss[0] - rot_90_vec * cap_size;
971 immVertex2fv(shdr_pos_2d, cap);
972 }
973
974 if (proj_ok[2]) {
975 cap = co_ss[2] + rot_90_vec * cap_size;
976 immVertex2fv(shdr_pos_2d, cap);
977 cap = co_ss[2] - rot_90_vec * cap_size;
978 immVertex2fv(shdr_pos_2d, cap);
979 }
980
981 immEnd();
982 }
983
985 }
986
987 /* text */
988 char numstr[256];
989 float2 numstr_size;
990 const int prec = 6; /* XXX, todo, make optional */
991 float2 posit;
992
993 ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
994
995 BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
996
997 posit = (co_ss[0] + co_ss[2]) / 2.0f;
998
999 /* center text */
1000 posit -= numstr_size / 2.0f;
1001
1002 /* Adjust text position if this helps readability. */
1003
1004 const float len = len_v2v2(co_ss[0], co_ss[2]);
1005
1006 if ((len < (numstr_size[1] * 2.5f)) ||
1007 ((len < (numstr_size[0] + bg_margin + bg_margin)) && (fabs(rot_90_vec[0]) < 0.5f)))
1008 {
1009 /* Super short, or quite short and also shallow angle. Position below line. */
1010 posit[1] = std::min(co_ss[0][1], co_ss[2][1]) - numstr_size[1] - bg_margin - bg_margin;
1011 }
1012 else if (fabs(rot_90_vec[0]) < 0.2f) {
1013 /* Very shallow angle. Shift down by text height. */
1014 posit[1] -= numstr_size[1];
1015 }
1016
1017 /* draw text (bg) */
1018 if (proj_ok[0] && proj_ok[2]) {
1019 immUniformColor4fv(color_back);
1021 immRectf(shdr_pos_2d,
1022 posit[0] - bg_margin,
1023 posit[1] - bg_margin,
1024 posit[0] + bg_margin + numstr_size[0],
1025 posit[1] + bg_margin + numstr_size[1]);
1027 }
1028
1030
1031 /* draw text */
1032 if (proj_ok[0] && proj_ok[2]) {
1033 BLF_color3ubv(blf_mono_font, color_text);
1034 BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
1035 BLF_draw(blf_mono_font, numstr, sizeof(numstr));
1036 }
1037 }
1038
1039 GPU_line_smooth(false);
1040
1042
1045}
1046
1047static int gizmo_ruler_test_select(bContext * /*C*/, wmGizmo *gz, const int mval[2])
1048{
1049 RulerItem *ruler_item_pick = (RulerItem *)gz;
1050 const float mval_fl[2] = {float(mval[0]), float(mval[1])};
1051 int co_index;
1052
1053 /* select and drag */
1054 if (view3d_ruler_pick(gz->parent_gzgroup, ruler_item_pick, mval_fl, &co_index)) {
1055 if (co_index == -1) {
1056 if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
1057 return PART_LINE;
1058 }
1059 }
1060 else {
1061 return co_index;
1062 }
1063 }
1064 return -1;
1065}
1066
1068 wmGizmo *gz,
1069 const wmEvent *event,
1070 eWM_GizmoFlagTweak tweak_flag)
1071{
1072 bool do_draw = false;
1074 RulerInfo *ruler_info = static_cast<RulerInfo *>(gz->parent_gzgroup->customdata);
1075 RulerItem *ruler_item = (RulerItem *)gz;
1076 ARegion *region = CTX_wm_region(C);
1077 bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE);
1078
1079 ruler_info->region = region;
1080
1081#ifdef USE_AXIS_CONSTRAINTS
1082 if ((event->val == KM_PRESS) && ELEM(event->type, EVT_XKEY, EVT_YKEY, EVT_ZKEY)) {
1083 /* Go to Mode 1 if a new axis is selected. */
1084 if (event->type == EVT_XKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_X) {
1085 ruler_info->constrain_axis = CONSTRAIN_AXIS_X;
1086 ruler_info->constrain_mode = CONSTRAIN_MODE_1;
1087 }
1088 else if (event->type == EVT_YKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_Y) {
1089 ruler_info->constrain_axis = CONSTRAIN_AXIS_Y;
1090 ruler_info->constrain_mode = CONSTRAIN_MODE_1;
1091 }
1092 else if (event->type == EVT_ZKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_Z) {
1093 ruler_info->constrain_axis = CONSTRAIN_AXIS_Z;
1094 ruler_info->constrain_mode = CONSTRAIN_MODE_1;
1095 }
1096 else {
1097 /* Cycle to the next mode if the same key is pressed again. */
1098 if (ruler_info->constrain_mode != CONSTRAIN_MODE_2) {
1099 ruler_info->constrain_mode++;
1100 }
1101 else {
1102 ruler_info->constrain_mode = CONSTRAIN_MODE_OFF;
1103 ruler_info->constrain_axis = CONSTRAIN_AXIS_NONE;
1104 }
1105 }
1106 do_cursor_update = true;
1107 }
1108#endif
1109
1110#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
1111 const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP);
1112#else
1113 /* Ensure snap is up to date. */
1115 C, ruler_info->snap_data.gizmo, nullptr, nullptr, nullptr, nullptr);
1116 const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo);
1117#endif
1118
1119 const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE;
1120 if (ruler_info->drag_state_prev.do_thickness != do_thickness) {
1121 do_cursor_update = true;
1122 }
1123
1124 if (do_cursor_update) {
1125 if (ruler_info->state == RULER_STATE_DRAG) {
1128 C, depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap))
1129 {
1130 do_draw = true;
1131 }
1132 }
1133 }
1134
1135 ruler_info->drag_state_prev.do_thickness = do_thickness;
1136
1137 if (do_draw) {
1139 }
1140 return exit_code;
1141}
1142
1144{
1145 wmGizmoGroup *gzgroup = gz->parent_gzgroup;
1146 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1147 RulerItem *ruler_item_pick = (RulerItem *)gz;
1149 gz->interaction_data = inter;
1150
1151 ARegion *region = ruler_info->region;
1152
1153 float mval_fl[2];
1154 WM_event_drag_start_mval_fl(event, region, mval_fl);
1155
1156#ifdef USE_AXIS_CONSTRAINTS
1157 ruler_info->constrain_axis = CONSTRAIN_AXIS_NONE;
1158 ruler_info->constrain_mode = CONSTRAIN_MODE_OFF;
1159#endif
1160
1161 /* select and drag */
1162 if (gz->highlight_part == PART_LINE) {
1163 if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
1164 /* Add Center Point */
1165 ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
1166 inter->co_index = 1;
1167 ruler_state_set(ruler_info, RULER_STATE_DRAG);
1168
1169 /* find the factor */
1170 {
1171 float2x2 co_ss;
1172 float fac;
1173
1175 region, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP);
1177 region, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP);
1178
1179 fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]);
1180 CLAMP(fac, 0.0f, 1.0f);
1181
1182 ruler_item_pick->co[1] = blender::math::interpolate(
1183 ruler_item_pick->co[0], ruler_item_pick->co[2], fac);
1184 }
1185
1186 /* update the new location */
1189 C, depsgraph, ruler_info, ruler_item_pick, event->mval, false, false);
1190 }
1191 }
1192 else {
1193 inter->co_index = gz->highlight_part;
1194 ruler_state_set(ruler_info, RULER_STATE_DRAG);
1195
1196 /* store the initial depth */
1197 inter->drag_start_co = ruler_item_pick->co[inter->co_index];
1198 }
1199
1200 if (inter->co_index == 1) {
1201 ruler_item_pick->flag |= RULERITEM_USE_ANGLE_ACTIVE;
1202 }
1203 else {
1204 ruler_item_pick->flag &= ~RULERITEM_USE_ANGLE_ACTIVE;
1205 }
1206
1207 {
1208 /* Set Snap prev point. */
1209 float3 *prev_point;
1210 eSnapMode snap_type;
1211 if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) {
1212 prev_point = (inter->co_index != 1) ? &ruler_item_pick->co[1] : nullptr;
1213 snap_type = (inter->co_index != 1) ? ruler_item_pick->snap_type[1] : SCE_SNAP_TO_VERTEX;
1214 }
1215 else if (inter->co_index == 0) {
1216 prev_point = &ruler_item_pick->co[2];
1217 snap_type = ruler_item_pick->snap_type[2];
1218 }
1219 else {
1220 prev_point = &ruler_item_pick->co[0];
1221 snap_type = ruler_item_pick->snap_type[2];
1222 }
1223
1224 if (prev_point) {
1226 ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point);
1228 ruler_info->snap_data.prop_snap_source_type,
1229 snap_type);
1230 }
1231 else {
1232 RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
1233 }
1234 }
1235
1236 ruler_info->item_active = ruler_item_pick;
1237
1238 /* Ensures there is a valid GPencil data in current scene. */
1240
1242}
1243
1244static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
1245{
1246 wmGizmoGroup *gzgroup = gz->parent_gzgroup;
1247 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1248
1249 if (!cancel) {
1250 if (ruler_info->state == RULER_STATE_DRAG) {
1251 RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
1253 }
1254 /* We could convert only the current gizmo, for now just re-generate. */
1255 if (view3d_ruler_to_gpencil(C, gzgroup)) {
1256 /* For immediate update when a ruler annotation layer was added. */
1258 }
1259 }
1260
1261 RulerInteraction *inter = static_cast<RulerInteraction *>(gz->interaction_data);
1262 MEM_freeN(inter);
1263 gz->interaction_data = nullptr;
1264
1266}
1267
1269{
1270 if (gz->highlight_part == PART_LINE) {
1271 return WM_CURSOR_CROSS;
1272 }
1273 return WM_CURSOR_NSEW_SCROLL;
1274}
1275
1277{
1278 /* identifiers */
1279 gzt->idname = "VIEW3D_GT_ruler_item";
1280
1281 /* API callbacks. */
1282 gzt->draw = gizmo_ruler_draw;
1284 gzt->modal = gizmo_ruler_modal;
1286 gzt->exit = gizmo_ruler_exit;
1288
1289 gzt->struct_size = sizeof(RulerItem);
1290}
1291
1293
1294/* -------------------------------------------------------------------- */
1297
1298static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
1299{
1300 RulerInfo *ruler_info = MEM_callocN<RulerInfo>(__func__);
1301
1302 wmGizmo *gizmo;
1303 {
1304 /* The gizmo snap has to be the first gizmo. */
1305 const wmGizmoType *gzt_snap;
1306 gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
1307 gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, nullptr);
1308
1310 WM_gizmo_set_color(gizmo, blender::float4(1.0f));
1311
1312 wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
1313 WM_gizmo_operator_set(gizmo, 0, ot, nullptr);
1314 }
1315
1316 if (view3d_ruler_from_gpencil(C, gzgroup)) {
1317 /* nop */
1318 }
1319
1321 wmWindow *win = CTX_wm_window(C);
1322 ScrArea *area = CTX_wm_area(C);
1323 ARegion *region = CTX_wm_region(C);
1324
1325 ruler_info->wm = wm;
1326 ruler_info->win = win;
1327 ruler_info->area = area;
1328 ruler_info->region = region;
1329 ruler_info->snap_data.gizmo = gizmo;
1330 ruler_info->snap_data.prop_prevpoint = RNA_struct_find_property(gizmo->ptr, "prev_point");
1332 "snap_source_type");
1333
1334 gzgroup->customdata = ruler_info;
1335}
1336
1350
1352
1353/* -------------------------------------------------------------------- */
1356
1358{
1360 if ((tref_rt == nullptr) || !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) ||
1361 CTX_wm_region_view3d(C) == nullptr)
1362 {
1363 return false;
1364 }
1365 return true;
1366}
1367
1369{
1370 ARegion *region = CTX_wm_region(C);
1371 View3D *v3d = CTX_wm_view3d(C);
1372
1374 BKE_report(op->reports, RPT_WARNING, "Gizmos hidden in this view");
1375 return OPERATOR_CANCELLED;
1376 }
1377
1378 wmGizmoMap *gzmap = region->runtime->gizmo_map;
1380
1381 if (!gizmo_ruler_check_for_operator(gzgroup)) {
1382 return OPERATOR_CANCELLED;
1383 }
1384
1385 int mval[2];
1386 WM_event_drag_start_mval(event, region, mval);
1387
1388 /* Create new line */
1389 RulerItem *ruler_item;
1390 ruler_item = ruler_item_add(gzgroup);
1391
1392 /* This is a little weak, but there is no real good way to tweak directly. */
1393 WM_gizmo_highlight_set(gzmap, &ruler_item->gz);
1395 C, "GIZMOGROUP_OT_gizmo_tweak", blender::wm::OpCallContext::InvokeRegionWin, nullptr, event);
1397 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1398 RulerInteraction *inter = static_cast<RulerInteraction *>(ruler_item->gz.interaction_data);
1400 inter->co_index = 0;
1401
1402#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
1403 /* Snap the first point added, not essential but handy. */
1404 const bool do_snap = true;
1405#else
1406 const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo);
1407#endif
1408
1409 view3d_ruler_item_mousemove(C, depsgraph, ruler_info, ruler_item, mval, false, do_snap);
1410 copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]);
1412 ruler_info->snap_data.prop_prevpoint,
1413 inter->drag_start_co);
1415 ruler_info->snap_data.prop_snap_source_type,
1416 ruler_item->snap_type[inter->co_index]);
1417
1418 copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);
1419 ruler_item->gz.highlight_part = inter->co_index = 2;
1420 }
1421 return OPERATOR_FINISHED;
1422}
1423
1425{
1426 /* identifiers */
1427 ot->name = "Ruler Add";
1428 ot->idname = "VIEW3D_OT_ruler_add";
1429 ot->description = "Add ruler";
1430
1431 ot->invoke = view3d_ruler_add_invoke;
1432 ot->poll = view3d_ruler_poll;
1433
1434 /* flags */
1435 ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1436}
1437
1439
1440/* -------------------------------------------------------------------- */
1443
1445 wmOperator *op,
1446 const wmEvent * /*event*/)
1447{
1448 ARegion *region = CTX_wm_region(C);
1449 View3D *v3d = CTX_wm_view3d(C);
1450
1452 BKE_report(op->reports, RPT_WARNING, "Gizmos hidden in this view");
1453 return OPERATOR_PASS_THROUGH;
1454 }
1455
1456 wmGizmoMap *gzmap = region->runtime->gizmo_map;
1458 if (gzgroup) {
1459 if (!gizmo_ruler_check_for_operator(gzgroup)) {
1460 return OPERATOR_CANCELLED;
1461 }
1462 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1463 if (ruler_info->item_active) {
1464 RulerItem *ruler_item = ruler_info->item_active;
1465 if ((ruler_item->flag & RULERITEM_USE_ANGLE) &&
1466 (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE))
1467 {
1469 }
1470 else {
1471 ruler_item_remove(C, gzgroup, ruler_item);
1472 }
1473
1474 /* Update the annotation layer. */
1476 view3d_ruler_to_gpencil(C, gzgroup);
1477
1479 return OPERATOR_FINISHED;
1480 }
1481 }
1482 return OPERATOR_PASS_THROUGH;
1483}
1484
1486{
1487 /* identifiers */
1488 ot->name = "Ruler Remove";
1489 ot->idname = "VIEW3D_OT_ruler_remove";
1490
1492 ot->poll = view3d_ruler_poll;
1493
1494 /* flags */
1495 ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1496}
1497
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf)
struct bGPDlayer * BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive, bool add_to_header)
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
struct bGPdata * BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
@ GP_GETFRAME_ADD_NEW
@ GP_GETFRAME_USE_PREV
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
int BKE_scene_orientation_get_index(Scene *scene, int slot_index)
Definition scene.cc:2439
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
@ B_UNIT_LENGTH
Definition BKE_unit.hh:137
@ B_UNIT_ROTATION
Definition BKE_unit.hh:141
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
size_t BKE_unit_value_as_string_scaled(char *str, int str_maxncpy, double value, int prec, int type, const UnitSettings &settings, bool pad)
Definition unit.cc:1895
void BLF_size(int fontid, float size)
Definition blf.cc:443
void BLF_enable(int fontid, FontFlags flag)
Definition blf.cc:320
void BLF_color3ubv(int fontid, const unsigned char rgb[3])
Definition blf.cc:476
void BLF_width_and_height(int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL()
Definition blf.cc:789
void BLF_rotation(int fontid, float angle)
Definition blf.cc:903
void BLF_draw(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:585
int blf_mono_font
Definition blf.cc:48
void BLF_disable(int fontid, FontFlags flag)
Definition blf.cc:329
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:388
@ BLF_ROTATION
Definition BLF_enums.hh:33
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
MINLINE float min_ff(float a, float b)
MINLINE float min_fff(float a, float b, float c)
#define RAD2DEGF(_rad)
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
MINLINE int min_axis_v3(const float vec[3])
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:291
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void mul_qt_v3(const float q[4], float r[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float normalize_v2(float n[2])
MINLINE void copy_v3_fl(float r[3], float f)
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_fl(float r[2], float f)
size_t size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define BLI_STR_UTF8_DEGREE_SIGN
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define UNPACK2(a)
#define UNUSED_VARS(...)
#define UNPACK3(a)
#define ELEM(...)
#define STREQ(a, b)
void DEG_relations_tag_update(Main *bmain)
ViewLayer * DEG_get_input_view_layer(const Depsgraph *graph)
Scene * DEG_get_input_scene(const Depsgraph *graph)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
Object is a sort of wrapper for general info.
@ SCE_ORIENT_DEFAULT
#define OBEDIT_FROM_OBACT(ob)
#define SCE_SNAP_TO_VERTEX
@ SCE_SNAP_TARGET_ALL
@ USER_UNIT_NONE
@ SCE_SNAP_TO_FACE
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
#define UI_SCALE_FAC
@ V3D_GIZMO_HIDE_TOOL
@ V3D_GIZMO_HIDE
@ V3D_ORIENT_GLOBAL
@ V3D_ORIENT_LOCAL
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:654
@ V3D_PROJ_TEST_CLIP_NEAR
Definition ED_view3d.hh:282
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:279
void ED_view3d_win_to_3d_int(const View3D *v3d, const ARegion *region, const float depth_pt[3], const int mval[2], float r_out[3])
float ED_view3d_pixel_size_no_ui_scale(const RegionView3D *rv3d, const float co[3])
eV3DProjStatus
Definition ED_view3d.hh:255
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
@ V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE
Definition ED_view3d.hh:334
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void immUniform4f(const char *name, float x, float y, float z, float w)
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immUniform2f(const char *name, float x, float y)
void immVertex2f(uint attr_id, float x, float y)
void immVertex2fv(uint attr_id, const float data[2])
void immUniformColor3ubv(const unsigned char rgb[3])
void immUniform1i(const char *name, int x)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immUniform4fv(const char *name, const float data[4])
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fv(const float rgb[3])
void immRectf(uint pos, float x1, float y1, float x2, float y2)
void GPU_matrix_identity_set()
#define GPU_matrix_set(x)
void GPU_matrix_push()
void GPU_matrix_push_projection()
void GPU_matrix_pop_projection()
#define GPU_matrix_projection_set(x)
void GPU_matrix_pop()
@ GPU_PRIM_LINES
@ GPU_PRIM_LINE_STRIP
@ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_line_width(float width)
Definition gpu_state.cc:166
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ TH_WIRE
@ TH_TEXT
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
eWM_GizmoFlagTweak
Gizmo tweak flag. Bit-flag passed to gizmo while tweaking.
@ WM_GIZMO_TWEAK_PRECISE
@ WM_GIZMO_TWEAK_SNAP
@ WM_GIZMO_DRAW_VALUE
@ WM_GIZMO_DRAW_MODAL
@ WM_GIZMOGROUPTYPE_SCALE
@ WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL
@ WM_GIZMOGROUPTYPE_3D
@ KM_PRESS
Definition WM_types.hh:311
@ KM_RELEASE
Definition WM_types.hh:312
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
#define NA_EDITED
Definition WM_types.hh:584
#define NC_GPENCIL
Definition WM_types.hh:399
#define U
BPy_StructRNA * depsgraph
nullptr float
uint col
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 fabs(const float2 a)
static ulong state[N]
#define MVAL_MAX_PX_DIST
eSnapMode snap_object_project_view3d(SnapObjectContext *sctx, Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const eSnapMode snap_to, const SnapObjectParams *params, const float init_co[3], const float mval[2], const float prev_co[3], float *dist_px, float r_loc[3], float r_no[3])
short calc_orientation_from_type_ex(const Scene *scene, ViewLayer *view_layer, const View3D *v3d, const RegionView3D *rv3d, Object *ob, Object *obedit, short orientation_index, int pivot_point, float r_mat[3][3])
bool snap_object_project_ray(SnapObjectContext *sctx, Depsgraph *depsgraph, const View3D *v3d, const SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], float *ray_depth, float r_co[3], float r_no[3])
T distance(const T &a, const T &b)
CartesianBasis invert(const CartesianBasis &basis)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
T interpolate(const T &a, const T &b, const FactorT &t)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
MatBase< float, 2, 2 > float2x2
VecBase< float, 4 > float4
VecBase< float, 2 > float2
MatBase< float, 3, 2 > float3x2
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
const int status
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop)
void ED_gizmotypes_snap_3d_data_get(const bContext *C, wmGizmo *gz, float r_loc[3], float r_nor[3], int r_elem_index[3], eSnapMode *r_snap_elem)
blender::ed::transform::SnapObjectContext * ED_gizmotypes_snap_3d_context_ensure(Scene *scene, wmGizmo *)
bool ED_gizmotypes_snap_3d_is_enabled(const wmGizmo *)
void ED_gizmotypes_snap_3d_flag_set(wmGizmo *gz, int flag)
void * regiondata
ARegionRuntimeHandle * runtime
void * first
float viewmat[4][4]
float winmat[4][4]
PropertyRNA * prop_snap_source_type
wmWindowManager * wm
struct RulerInfo::@244002166313060124365335164133104061357331232157 drag_state_prev
struct RulerInfo::@102167245014366230146170070050104033360237315112 snap_data
PropertyRNA * prop_prevpoint
RulerItem * item_active
eSnapMode snap_type[3]
struct ToolSettings * toolsettings
struct bGPdata * gpd
struct RenderData r
struct UnitSettings unit
ListBase spacedata
ListBase areabase
const c_style_mat & ptr() const
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
wmGizmoGroupFnInit setup
const char * idname
wmGizmoMapType_Params gzmap_params
eWM_GizmoFlagGroupTypeFlag flag
wmGizmoGroupFnPoll poll
wmGizmoMap * parent_gzmap
wmGizmoFnDraw draw
wmGizmoFnModal modal
const char * idname
wmGizmoFnTestSelect test_select
wmGizmoFnExit exit
wmGizmoFnCursorGet cursor_get
wmGizmoFnInvoke invoke
wmGizmoGroup * parent_gzgroup
void * interaction_data
PointerRNA * ptr
wmGizmo * next
struct ReportList * reports
i
Definition text_draw.cc:230
uint len
static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
static bGPDlayer * view3d_ruler_layer_get(bGPdata *gpd)
static void ruler_item_remove(bContext *C, wmGizmoGroup *gzgroup, RulerItem *ruler_item)
@ RULER_STATE_DRAG
@ RULER_STATE_NORMAL
static bool gizmo_ruler_check_for_operator(const wmGizmoGroup *gzgroup)
static bool view3d_ruler_poll(bContext *C)
static void ruler_state_set(RulerInfo *ruler_info, int state)
static const char * view3d_gzgt_ruler_id
@ RULERITEM_USE_ANGLE
@ RULERITEM_USE_ANGLE_ACTIVE
void VIEW3D_OT_ruler_remove(wmOperatorType *ot)
void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt)
static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
void VIEW3D_OT_ruler_add(wmOperatorType *ot)
@ CONSTRAIN_MODE_1
@ CONSTRAIN_MODE_OFF
@ CONSTRAIN_MODE_2
static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
static bool view3d_ruler_item_mousemove(const bContext *C, Depsgraph *depsgraph, RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2], const bool do_thickness, const bool do_snap)
static void ruler_item_as_string(RulerItem *ruler_item, const UnitSettings &unit, char *numstr, size_t numstr_size, int prec)
void ED_view3d_gizmo_ruler_remove_by_gpencil_layer(bContext *C, bGPDlayer *gpl)
static wmOperatorStatus view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int gizmo_ruler_test_select(bContext *, wmGizmo *gz, const int mval[2])
static wmOperatorStatus gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
@ CONSTRAIN_AXIS_Z
@ CONSTRAIN_AXIS_Y
@ CONSTRAIN_AXIS_NONE
@ CONSTRAIN_AXIS_X
static RulerItem * ruler_item_add(wmGizmoGroup *gzgroup)
static int gizmo_ruler_cursor_get(wmGizmo *gz)
#define PART_LINE
static wmOperatorStatus view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void view3d_ruler_item_project(RulerInfo *ruler_info, float3 &r_co, const int xy[2])
#define RULER_ID
static void view3d_ruler_gpencil_ensure(bContext *C)
static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
void VIEW3D_GT_ruler_item(wmGizmoType *gzt)
#define RULER_PICK_DIST_SQ
static RulerItem * gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup)
static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, RulerItem *ruler_item, const float2 mval, int *r_co_index)
static wmOperatorStatus gizmo_ruler_modal(bContext *C, wmGizmo *gz, const wmEvent *event, eWM_GizmoFlagTweak tweak_flag)
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:52
@ WM_CURSOR_CROSS
Definition wm_cursors.hh:26
int xy[2]
Definition wm_draw.cc:178
void WM_event_drag_start_mval_fl(const wmEvent *event, const ARegion *region, float r_mval[2])
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
@ EVT_YKEY
@ EVT_XKEY
@ MOUSEMOVE
@ EVT_ZKEY
wmOperatorType * ot
Definition wm_files.cc:4237
wmGizmo * WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, PointerRNA *properties)
Definition wm_gizmo.cc:85
bool WM_gizmo_highlight_set(wmGizmoMap *gzmap, wmGizmo *gz)
Definition wm_gizmo.cc:405
void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
Definition wm_gizmo.cc:307
PointerRNA * WM_gizmo_operator_set(wmGizmo *gz, int part_index, wmOperatorType *ot, IDProperty *properties)
Definition wm_gizmo.cc:203
void WM_gizmo_set_color(wmGizmo *gz, const float color[4])
Definition wm_gizmo.cc:331
void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)
Definition wm_gizmo.cc:165
wmGizmoGroup * WM_gizmomap_group_find(wmGizmoMap *gzmap, const char *idname)
const wmGizmoType * WM_gizmotype_find(const StringRef idname, bool quiet)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void wmOrtho2_region_pixelspace(const ARegion *region)
bToolRef_Runtime * WM_toolsystem_runtime_from_context(const bContext *C)
Scene * WM_window_get_active_scene(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)