Blender V4.3
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
9#include "BLI_listbase.h"
10#include "BLI_math_matrix.hh"
12#include "BLI_math_rotation.h"
14#include "BLI_string.h"
15#include "BLI_utildefines.h"
16
17#include "BKE_context.hh"
18#include "BKE_gpencil_legacy.h"
19#include "BKE_report.hh"
20
21#include "BKE_layer.hh"
22#include "BKE_scene.hh"
23#include "BKE_unit.hh"
24
26#include "DNA_object_types.h"
27#include "DNA_view3d_types.h"
28
29#include "ED_gizmo_library.hh"
30#include "ED_gizmo_utils.hh"
31#include "ED_screen.hh"
32#include "ED_transform.hh"
34#include "ED_view3d.hh"
35
36#include "UI_interface.hh"
37#include "UI_resources.hh"
38
39#include "MEM_guardedalloc.h"
40
41#include "RNA_access.hh"
42
43#include "WM_api.hh"
44#include "WM_toolsystem.hh"
45#include "WM_types.hh"
46
48
49#include "view3d_intern.hh" /* own include */
50
51#include "GPU_immediate.hh"
52#include "GPU_immediate_util.hh"
53#include "GPU_matrix.hh"
54#include "GPU_state.hh"
55
56#include "BLF_api.hh"
57
58using blender::float2;
60using blender::float3;
63using blender::float4;
64
69#define USE_AXIS_CONSTRAINTS
70
71static const char *view3d_gzgt_ruler_id = "VIEW3D_GGT_ruler";
72
73#define MVAL_MAX_PX_DIST 12.0f
74
75/* -------------------------------------------------------------------- */
76/* Ruler Item (we can have many) */
77
78enum {
83};
84
85/* keep smaller than selection, since we may want click elsewhere without selecting a ruler */
86#define RULER_PICK_DIST 12.0f
87#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST)
88
89/* not clicking on a point */
90#define PART_LINE 0xff
91
92/* -------------------------------------------------------------------- */
93/* Ruler Info (wmGizmoGroup customdata) */
94
95enum {
98};
99
100#ifdef USE_AXIS_CONSTRAINTS
101/* Constrain axes */
102enum {
107};
108
113enum {
117};
118#endif /* USE_AXIS_CONSTRAINTS */
119
120struct RulerItem;
121
122struct RulerInfo {
124 int flag;
126 int state;
127
128#ifdef USE_AXIS_CONSTRAINTS
130#endif
131
132 /* wm state */
136 ARegion *region; /* re-assigned every modal update */
137
138 /* Track changes in state. */
139 struct {
140#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
141 bool do_snap;
142#endif
145
146 struct {
151};
152
153/* -------------------------------------------------------------------- */
154/* Ruler Item (two or three points) */
155
156struct RulerItem {
158
160 float3x3 co;
162
163 int flag;
164 int raycast_dir; /* RULER_DIRECTION_* */
165};
166
168 /* selected coord */
169 char co_index; /* 0 -> 2 */
171};
172
173/* -------------------------------------------------------------------- */
178{
179 /* could pass this as an arg */
180 const wmGizmoType *gzt_ruler = WM_gizmotype_find("VIEW3D_GT_ruler_item", true);
181 RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, nullptr);
182 WM_gizmo_set_flag(&ruler_item->gz, WM_GIZMO_DRAW_MODAL, true);
183 return ruler_item;
184}
185
186static void ruler_item_remove(bContext *C, wmGizmoGroup *gzgroup, RulerItem *ruler_item)
187{
188 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
189 if (ruler_info->item_active == ruler_item) {
190 ruler_info->item_active = nullptr;
191 }
192 WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, &ruler_item->gz, C);
193}
194
196 RulerItem *ruler_item, UnitSettings *unit, char *numstr, size_t numstr_size, int prec)
197{
198 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
199 const float ruler_angle = angle_v3v3v3(
200 ruler_item->co[0], ruler_item->co[1], ruler_item->co[2]);
201
202 if (unit->system == USER_UNIT_NONE) {
204 numstr, numstr_size, "%.*f" BLI_STR_UTF8_DEGREE_SIGN, prec, RAD2DEGF(ruler_angle));
205 }
206 else {
208 numstr, numstr_size, double(ruler_angle), prec, B_UNIT_ROTATION, unit, false);
209 }
210 }
211 else {
212 const float ruler_len = len_v3v3(ruler_item->co[0], ruler_item->co[2]);
213
214 if (unit->system == USER_UNIT_NONE) {
215 BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len);
216 }
217 else {
219 numstr_size,
220 double(ruler_len * unit->scale_length),
221 prec,
223 unit,
224 false);
225 }
226 }
227}
228
229static bool view3d_ruler_pick(wmGizmoGroup *gzgroup,
230 RulerItem *ruler_item,
231 const float2 mval,
232 int *r_co_index)
233{
234 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
235 ARegion *region = ruler_info->region;
236 bool found = false;
237
238 float dist_best = RULER_PICK_DIST_SQ;
239 int co_index_best = -1;
240
241 {
242 float3x2 co_ss;
243 float dist;
244 int j;
245
246 /* should these be checked? - ok for now not to */
247 for (j = 0; j < 3; j++) {
248 ED_view3d_project_float_global(region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
249 }
250
251 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
252 dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]),
253 dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2]));
254 if (dist < dist_best) {
255 dist_best = dist;
256 found = true;
257
258 {
259 const float3 dist_points = {
260 blender::math::distance_squared(co_ss[0], mval),
261 blender::math::distance_squared(co_ss[1], mval),
262 blender::math::distance_squared(co_ss[2], mval),
263 };
264 if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) {
265 co_index_best = min_axis_v3(dist_points);
266 }
267 else {
268 co_index_best = -1;
269 }
270 }
271 }
272 }
273 else {
274 dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]);
275 if (dist < dist_best) {
276 dist_best = dist;
277 found = true;
278
279 {
280 const float2 dist_points = {
281 blender::math::distance_squared(co_ss[0], mval),
282 blender::math::distance_squared(co_ss[2], mval),
283 };
284 if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) {
285 co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2;
286 }
287 else {
288 co_index_best = -1;
289 }
290 }
291 }
292 }
293 }
294 UNUSED_VARS(dist_best);
295
296 *r_co_index = co_index_best;
297 return found;
298}
299
304static void ruler_state_set(RulerInfo *ruler_info, int state)
305{
306 if (state == ruler_info->state) {
307 return;
308 }
309
310 if (state == RULER_STATE_NORMAL) {
313 ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, nullptr);
314 }
315 else if (state == RULER_STATE_DRAG) {
316 memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev));
317
318 /* Force the snap cursor to appear even though it is not highlighted. */
320 }
321 else {
322 BLI_assert(0);
323 }
324
325 ruler_info->state = state;
326}
327
328static void view3d_ruler_item_project(RulerInfo *ruler_info, float3 &r_co, const int xy[2])
329{
330 ED_view3d_win_to_3d_int(static_cast<const View3D *>(ruler_info->area->spacedata.first),
331 ruler_info->region,
332 r_co,
333 xy,
334 r_co);
335}
336
341 Depsgraph *depsgraph,
342 RulerInfo *ruler_info,
343 RulerItem *ruler_item,
344 const int mval[2],
345 const bool do_thickness,
346 const bool do_snap)
347{
348 wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo;
349 constexpr float eps_bias = 0.0002f;
350 float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
351
352 if (ruler_item) {
353 RulerInteraction *inter = static_cast<RulerInteraction *>(ruler_item->gz.interaction_data);
354 float3 &co = ruler_item->co[inter->co_index];
355 eSnapMode *snap_source_type = &ruler_item->snap_type[inter->co_index];
356 /* restore the initial depth */
357 co = inter->drag_start_co;
358 view3d_ruler_item_project(ruler_info, co, mval);
359 if (do_thickness && inter->co_index != 1) {
361 View3D *v3d = static_cast<View3D *>(ruler_info->area->spacedata.first);
362 SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(scene, snap_gizmo);
363 const float2 mval_fl = {float(mval[0]), float(mval[1])};
364 float3 ray_normal;
365 float3 ray_start;
366 float3 &co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0];
367
368 SnapObjectParams snap_object_params{};
369 snap_object_params.snap_target_select = SCE_SNAP_TARGET_ALL;
370 snap_object_params.edit_mode_type = SNAP_GEOM_CAGE;
371
373 depsgraph,
374 ruler_info->region,
375 v3d,
377 &snap_object_params,
378 nullptr,
379 mval_fl,
380 nullptr,
381 &dist_px,
382 co,
383 ray_normal);
384 if (hit) {
385 /* add some bias */
386 ray_start = co - ray_normal * eps_bias;
388 depsgraph,
389 v3d,
390 &snap_object_params,
391 ray_start,
392 -ray_normal,
393 nullptr,
394 co_other,
395 nullptr);
396 }
397 }
398 else {
399 View3D *v3d = static_cast<View3D *>(ruler_info->area->spacedata.first);
400 if (do_snap) {
401 float3 *prev_point = nullptr;
402 eSnapMode snap_type;
404
405 if (inter->co_index != 1) {
406 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
407 prev_point = &ruler_item->co[1];
408 snap_type = ruler_item->snap_type[1];
409 }
410 else if (inter->co_index == 0) {
411 prev_point = &ruler_item->co[2];
412 snap_type = ruler_item->snap_type[2];
413 }
414 else {
415 prev_point = &ruler_item->co[0];
416 snap_type = ruler_item->snap_type[0];
417 }
418 }
419 if (prev_point != nullptr) {
421 snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point);
423 snap_gizmo->ptr, ruler_info->snap_data.prop_snap_source_type, snap_type);
424 }
425
426 ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, nullptr, nullptr, snap_source_type);
427 }
428
429#ifdef USE_AXIS_CONSTRAINTS
430 if (!(ruler_item->flag & RULERITEM_USE_ANGLE) &&
431 ruler_info->constrain_mode != CONSTRAIN_MODE_OFF)
432 {
433
436 RegionView3D *rv3d = static_cast<RegionView3D *>(ruler_info->region->regiondata);
437 BKE_view_layer_synced_ensure(scene, view_layer);
439 Object *obedit = OBEDIT_FROM_OBACT(ob);
440
441 short orient_index = BKE_scene_orientation_get_index(scene, SCE_ORIENT_DEFAULT);
442
443 if (ruler_info->constrain_mode == CONSTRAIN_MODE_2) {
444 orient_index = (orient_index == V3D_ORIENT_GLOBAL) ? V3D_ORIENT_LOCAL :
446 }
447
448 const int pivot_point = scene->toolsettings->transform_pivot_point;
449 float3x3 mat;
450
452 scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat.ptr());
453
454 ruler_item->co = blender::math::invert(mat) * ruler_item->co;
455
456 /* Loop through the axes and constrain the dragged point to the current constrained axis.
457 */
458 for (int i = 0; i <= 2; i++) {
459 if (ruler_info->constrain_axis != i) {
460 ruler_item->co[inter->co_index][i] = ruler_item->co[(inter->co_index == 0) ? 2 : 0][i];
461 }
462 }
463 ruler_item->co = mat * ruler_item->co;
464 }
465#endif
466 }
467 return true;
468 }
469 return false;
470}
471
481{
482 return gzgroup->customdata != nullptr;
483}
484
487/* -------------------------------------------------------------------- */
491/* Helper: Find the layer created as ruler. */
493{
494 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
495 if (gpl->flag & GP_LAYER_IS_RULER) {
496 return gpl;
497 }
498 }
499 return nullptr;
500}
501
503{
504#ifndef NDEBUG
505 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
506 BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo);
507#endif
508 return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next;
509}
510
511#define RULER_ID "RulerData3D"
512
513/* GP data creation has to happen before the undo step is stored.
514 * See also #116734. */
516{
517 // RulerInfo *ruler_info = gzgroup->customdata;
518 Main *bmain = CTX_data_main(C);
519 Scene *scene = CTX_data_scene(C);
520 if (scene->gpd == nullptr) {
521 scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
524 }
525}
526
528{
529 // RulerInfo *ruler_info = gzgroup->customdata;
530 Scene *scene = CTX_data_scene(C);
531
532 bGPdata *gpd;
533 bGPDlayer *gpl;
534 bGPDframe *gpf;
535 bGPDstroke *gps;
536 RulerItem *ruler_item;
537 const char *ruler_name = RULER_ID;
538 bool changed = false;
539
540 BLI_assert(scene->gpd != nullptr);
541 gpd = scene->gpd;
542
543 gpl = view3d_ruler_layer_get(gpd);
544 if (gpl == nullptr) {
545 gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false, false);
546 copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
547 gpl->thickness = 1;
549 }
550
551 gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
553
554 for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item;
555 ruler_item = (RulerItem *)ruler_item->gz.next)
556 {
557 bGPDspoint *pt;
558 int j;
559
560 /* allocate memory for a new stroke */
561 gps = (bGPDstroke *)MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
562 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
563 gps->totpoints = 3;
564 pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints,
565 "gp_stroke_points");
566 for (j = 0; j < 3; j++) {
567 copy_v3_v3(&pt->x, ruler_item->co[j]);
568 pt->pressure = 1.0f;
569 pt->strength = 1.0f;
570 pt++;
571 }
572 }
573 else {
574 gps->totpoints = 2;
575 pt = gps->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * gps->totpoints,
576 "gp_stroke_points");
577 for (j = 0; j < 3; j += 2) {
578 copy_v3_v3(&pt->x, ruler_item->co[j]);
579 pt->pressure = 1.0f;
580 pt->strength = 1.0f;
581 pt++;
582 }
583 }
584 gps->flag = GP_STROKE_3DSPACE;
585 gps->thickness = 3;
586 gps->hardness = 1.0f;
587 gps->fill_opacity_fac = 1.0f;
588 copy_v2_fl(gps->aspect_ratio, 1.0f);
589 gps->uv_scale = 1.0f;
590
591 BLI_addtail(&gpf->strokes, gps);
592 changed = true;
593 }
594
595 return changed;
596}
597
598static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
599{
600 Scene *scene = CTX_data_scene(C);
601 bool changed = false;
602
603 if (scene->gpd) {
604 bGPDlayer *gpl;
605 gpl = view3d_ruler_layer_get(scene->gpd);
606 if (gpl) {
607 bGPDframe *gpf;
608 gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
609 if (gpf) {
610 LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
611 bGPDspoint *pt = gps->points;
612 int j;
613 RulerItem *ruler_item = nullptr;
614 if (gps->totpoints == 3) {
615 ruler_item = ruler_item_add(gzgroup);
616 for (j = 0; j < 3; j++) {
617 copy_v3_v3(ruler_item->co[j], &pt->x);
618 pt++;
619 }
620 ruler_item->flag |= RULERITEM_USE_ANGLE;
621 changed = true;
622 }
623 else if (gps->totpoints == 2) {
624 ruler_item = ruler_item_add(gzgroup);
625 for (j = 0; j < 3; j += 2) {
626 copy_v3_v3(ruler_item->co[j], &pt->x);
627 pt++;
628 }
629 changed = true;
630 }
631 }
632 }
633 }
634 }
635
636 return changed;
637}
638
641/* -------------------------------------------------------------------- */
645static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
646{
647 Scene *scene = CTX_data_scene(C);
648 UnitSettings *unit = &scene->unit;
649 RulerInfo *ruler_info = static_cast<RulerInfo *>(gz->parent_gzgroup->customdata);
650 RulerItem *ruler_item = (RulerItem *)gz;
651 ARegion *region = ruler_info->region;
652 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
653 const float cap_size = 4.0f * UI_SCALE_FAC;
654 const float bg_margin = 4.0f * UI_SCALE_FAC;
655 const float arc_size = 64.0f * UI_SCALE_FAC;
656 constexpr int arc_steps = 24;
657 const float4 color_act = {1.0f, 1.0f, 1.0f, 1.0f};
658 const float4 color_base = {0.0f, 0.0f, 0.0f, 1.0f};
659 uchar color_text[3];
660 uchar color_wire[3];
661 float4 color_back = {1.0f, 1.0f, 1.0f, 0.5f};
662
663 /* Pixel Space. */
668
669 /* anti-aliased lines for more consistent appearance */
670 GPU_line_smooth(true);
671 GPU_line_width(1.0f);
672
676
677 UI_GetThemeColor3ubv(TH_TEXT, color_text);
678 UI_GetThemeColor3ubv(TH_WIRE, color_wire);
679
680 /* Avoid white on white text. (TODO: Fix by using theme). */
681 if (int(color_text[0]) + int(color_text[1]) + int(color_text[2]) > 127 * 3 * 0.6f) {
682 copy_v3_fl(color_back, 0.0f);
683 }
684
685 const bool is_act = (ruler_info->item_active == ruler_item);
686 float2 dir_ruler;
687 float3x2 co_ss;
688 bool proj_ok[3];
689 int j;
690
691 /* Check if each corner is behind the near plane. If it is, we do not draw certain lines. */
692 for (j = 0; j < 3; j++) {
694 region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_CLIP_NEAR);
695 proj_ok[j] = (status == V3D_PROJ_RET_OK);
696 }
697
698 /* 3d drawing. */
699
703 GPU_matrix_set(rv3d->viewmat);
704
706
707 const uint shdr_pos_3d = GPU_vertformat_attr_add(
709
710 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
712
713 float4 viewport_size(0.0f);
714 GPU_viewport_size_get_f(viewport_size);
715 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
716
717 immUniform1i("colors_len", 2); /* "advanced" mode */
718 const float4 &col = is_act ? color_act : color_base;
719 immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f);
720 immUniform4fv("color2", col);
721 immUniform1f("dash_width", 6.0f);
722 immUniform1f("udash_factor", 0.5f);
723
725
726 immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
727 immVertex3fv(shdr_pos_3d, ruler_item->co[1]);
728 immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
729
730 immEnd();
731
733
735
736 /* arc */
737 {
738 float3 dir_tmp;
739 float3 ar_coord;
740
741 float3 dir_a;
742 float3 dir_b;
743 float4 quat;
744 float3 axis;
745 float angle;
746 const float px_scale = (ED_view3d_pixel_size_no_ui_scale(rv3d, ruler_item->co[1]) *
747 min_fff(arc_size,
748 blender::math::distance(co_ss[0], co_ss[1]) / 2.0f,
749 blender::math::distance(co_ss[2], co_ss[1]) / 2.0f));
750
751 dir_a = blender::math::normalize(ruler_item->co[0] - ruler_item->co[1]);
752 dir_b = blender::math::normalize(ruler_item->co[2] - ruler_item->co[1]);
753 axis = blender::math::cross(dir_a, dir_b);
754 angle = angle_normalized_v3v3(dir_a, dir_b);
755
756 axis_angle_to_quat(quat, axis, angle / arc_steps);
757
758 dir_tmp = dir_a;
759
760 immUniformColor3ubv(color_wire);
761
762 immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1);
763
764 for (j = 0; j <= arc_steps; j++) {
765 ar_coord = ruler_item->co[1] + dir_tmp * px_scale;
766 mul_qt_v3(quat, dir_tmp);
767
768 immVertex3fv(shdr_pos_3d, ar_coord);
769 }
770
771 immEnd();
772 }
773
775 }
776 else {
778
779 float viewport_size[4];
780 GPU_viewport_size_get_f(viewport_size);
781 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
782
783 immUniform1i("colors_len", 2); /* "advanced" mode */
784 const float *col = is_act ? color_act : color_base;
785 immUniform4f("color", 0.67f, 0.67f, 0.67f, 1.0f);
786 immUniform4fv("color2", col);
787 immUniform1f("dash_width", 6.0f);
788 immUniform1f("udash_factor", 0.5f);
789
791
792 immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
793 immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
794
795 immEnd();
796
798 }
799
800 /* 2d drawing. */
801
804
805 const uint shdr_pos_2d = GPU_vertformat_attr_add(
807
808 if (ruler_item->flag & RULERITEM_USE_ANGLE) {
810 /* capping */
811 {
812 float2 cap;
813
814 dir_ruler = co_ss[0] - co_ss[1];
815 float2 rot_90_vec_a = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]});
816
817 dir_ruler = co_ss[1] - co_ss[2];
818 float2 rot_90_vec_b = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]});
819
821
822 if (proj_ok[1] && is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
823 GPU_line_width(3.0f);
824 immUniformColor3fv(color_act);
826 /* angle vertex */
827 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
828 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
829 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
830 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
831
832 immEnd();
833 GPU_line_width(1.0f);
834 }
835
836 immUniformColor3ubv(color_wire);
837
838 if (proj_ok[0] || proj_ok[2] || proj_ok[1]) {
839 immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4);
840
841 if (proj_ok[0]) {
842 cap = co_ss[0] + rot_90_vec_a * cap_size;
843 immVertex2fv(shdr_pos_2d, cap);
844 cap = co_ss[0] - rot_90_vec_a * cap_size;
845 immVertex2fv(shdr_pos_2d, cap);
846 }
847
848 if (proj_ok[2]) {
849 cap = co_ss[2] + rot_90_vec_b * cap_size;
850 immVertex2fv(shdr_pos_2d, cap);
851 cap = co_ss[2] - rot_90_vec_b * cap_size;
852 immVertex2fv(shdr_pos_2d, cap);
853 }
854
855 /* angle vertex */
856 if (proj_ok[1]) {
857 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
858 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
859 immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
860 immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
861 }
862
863 immEnd();
864 }
865
867 }
868
869 /* text */
870 char numstr[256];
871 float2 numstr_size;
872 float posit[2];
873 const int prec = 2; /* XXX, todo, make optional */
874
875 ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
876
877 BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
878
879 /* Center text. */
880 posit[0] = co_ss[1][0] - (numstr_size[0] / 2.0f);
881 posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
882
883 /* Adjust text position to help readability. */
884 sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
885 float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
886 normalize_v2(rot_90_vec);
887 posit[1] += rot_90_vec[0] * numstr_size[1];
888 posit[0] += (rot_90_vec[1] < 0) ? numstr_size[0] : -numstr_size[0];
889
890 /* draw text (bg) */
891 if (proj_ok[1]) {
892 immUniformColor4fv(color_back);
894 immRectf(shdr_pos_2d,
895 posit[0] - bg_margin,
896 posit[1] - bg_margin,
897 posit[0] + bg_margin + numstr_size[0],
898 posit[1] + bg_margin + numstr_size[1]);
900 }
901
903
904 /* draw text */
905 if (proj_ok[1]) {
906 BLF_color3ubv(blf_mono_font, color_text);
907 BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
909 BLF_draw(blf_mono_font, numstr, sizeof(numstr));
910 }
911 }
912 else {
914
915 dir_ruler = co_ss[0] - co_ss[2];
916 float2 rot_90_vec = blender::math::normalize(float2{-dir_ruler[1], dir_ruler[0]});
917
918 /* capping */
919 {
920 float2 cap;
921
923
924 immUniformColor3ubv(color_wire);
925
926 if (proj_ok[0] || proj_ok[2]) {
927 immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2);
928
929 if (proj_ok[0]) {
930 cap = co_ss[0] + rot_90_vec * cap_size;
931 immVertex2fv(shdr_pos_2d, cap);
932 cap = co_ss[0] - rot_90_vec * cap_size;
933 immVertex2fv(shdr_pos_2d, cap);
934 }
935
936 if (proj_ok[2]) {
937 cap = co_ss[2] + rot_90_vec * cap_size;
938 immVertex2fv(shdr_pos_2d, cap);
939 cap = co_ss[2] - rot_90_vec * cap_size;
940 immVertex2fv(shdr_pos_2d, cap);
941 }
942
943 immEnd();
944 }
945
947 }
948
949 /* text */
950 char numstr[256];
951 float2 numstr_size;
952 const int prec = 6; /* XXX, todo, make optional */
953 float2 posit;
954
955 ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
956
957 BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
958
959 posit = (co_ss[0] + co_ss[2]) / 2.0f;
960
961 /* center text */
962 posit -= numstr_size / 2.0f;
963
964 /* Adjust text position if this helps readability. */
965
966 const float len = len_v2v2(co_ss[0], co_ss[2]);
967
968 if ((len < (numstr_size[1] * 2.5f)) ||
969 ((len < (numstr_size[0] + bg_margin + bg_margin)) && (fabs(rot_90_vec[0]) < 0.5f)))
970 {
971 /* Super short, or quite short and also shallow angle. Position below line. */
972 posit[1] = std::min(co_ss[0][1], co_ss[2][1]) - numstr_size[1] - bg_margin - bg_margin;
973 }
974 else if (fabs(rot_90_vec[0]) < 0.2f) {
975 /* Very shallow angle. Shift down by text height. */
976 posit[1] -= numstr_size[1];
977 }
978
979 /* draw text (bg) */
980 if (proj_ok[0] && proj_ok[2]) {
981 immUniformColor4fv(color_back);
983 immRectf(shdr_pos_2d,
984 posit[0] - bg_margin,
985 posit[1] - bg_margin,
986 posit[0] + bg_margin + numstr_size[0],
987 posit[1] + bg_margin + numstr_size[1]);
989 }
990
992
993 /* draw text */
994 if (proj_ok[0] && proj_ok[2]) {
995 BLF_color3ubv(blf_mono_font, color_text);
996 BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
997 BLF_draw(blf_mono_font, numstr, sizeof(numstr));
998 }
999 }
1000
1001 GPU_line_smooth(false);
1002
1004
1007}
1008
1009static int gizmo_ruler_test_select(bContext *, wmGizmo *gz, const int mval[2])
1010{
1011 RulerItem *ruler_item_pick = (RulerItem *)gz;
1012 const float mval_fl[2] = {float(mval[0]), float(mval[1])};
1013 int co_index;
1014
1015 /* select and drag */
1016 if (view3d_ruler_pick(gz->parent_gzgroup, ruler_item_pick, mval_fl, &co_index)) {
1017 if (co_index == -1) {
1018 if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
1019 return PART_LINE;
1020 }
1021 }
1022 else {
1023 return co_index;
1024 }
1025 }
1026 return -1;
1027}
1028
1030 wmGizmo *gz,
1031 const wmEvent *event,
1032 eWM_GizmoFlagTweak tweak_flag)
1033{
1034 bool do_draw = false;
1035 int exit_code = OPERATOR_RUNNING_MODAL;
1036 RulerInfo *ruler_info = static_cast<RulerInfo *>(gz->parent_gzgroup->customdata);
1037 RulerItem *ruler_item = (RulerItem *)gz;
1038 ARegion *region = CTX_wm_region(C);
1039 bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE);
1040
1041 ruler_info->region = region;
1042
1043#ifdef USE_AXIS_CONSTRAINTS
1044 if ((event->val == KM_PRESS) && ELEM(event->type, EVT_XKEY, EVT_YKEY, EVT_ZKEY)) {
1045 /* Go to Mode 1 if a new axis is selected. */
1046 if (event->type == EVT_XKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_X) {
1047 ruler_info->constrain_axis = CONSTRAIN_AXIS_X;
1048 ruler_info->constrain_mode = CONSTRAIN_MODE_1;
1049 }
1050 else if (event->type == EVT_YKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_Y) {
1051 ruler_info->constrain_axis = CONSTRAIN_AXIS_Y;
1052 ruler_info->constrain_mode = CONSTRAIN_MODE_1;
1053 }
1054 else if (event->type == EVT_ZKEY && ruler_info->constrain_axis != CONSTRAIN_AXIS_Z) {
1055 ruler_info->constrain_axis = CONSTRAIN_AXIS_Z;
1056 ruler_info->constrain_mode = CONSTRAIN_MODE_1;
1057 }
1058 else {
1059 /* Cycle to the next mode if the same key is pressed again. */
1060 if (ruler_info->constrain_mode != CONSTRAIN_MODE_2) {
1061 ruler_info->constrain_mode++;
1062 }
1063 else {
1064 ruler_info->constrain_mode = CONSTRAIN_MODE_OFF;
1065 ruler_info->constrain_axis = CONSTRAIN_AXIS_NONE;
1066 }
1067 }
1068 do_cursor_update = true;
1069 }
1070#endif
1071
1072#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
1073 const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP);
1074#else
1075 /* Ensure snap is up to date. */
1077 C, ruler_info->snap_data.gizmo, nullptr, nullptr, nullptr, nullptr);
1078 const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo);
1079#endif
1080
1081 const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE;
1082 if (ruler_info->drag_state_prev.do_thickness != do_thickness) {
1083 do_cursor_update = true;
1084 }
1085
1086 if (do_cursor_update) {
1087 if (ruler_info->state == RULER_STATE_DRAG) {
1090 C, depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap))
1091 {
1092 do_draw = true;
1093 }
1094 }
1095 }
1096
1097 ruler_info->drag_state_prev.do_thickness = do_thickness;
1098
1099 if (do_draw) {
1101 }
1102 return exit_code;
1103}
1104
1105static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
1106{
1107 wmGizmoGroup *gzgroup = gz->parent_gzgroup;
1108 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1109 RulerItem *ruler_item_pick = (RulerItem *)gz;
1110 RulerInteraction *inter = (RulerInteraction *)MEM_callocN(sizeof(RulerInteraction), __func__);
1111 gz->interaction_data = inter;
1112
1113 ARegion *region = ruler_info->region;
1114
1115 float mval_fl[2];
1116 WM_event_drag_start_mval_fl(event, region, mval_fl);
1117
1118#ifdef USE_AXIS_CONSTRAINTS
1119 ruler_info->constrain_axis = CONSTRAIN_AXIS_NONE;
1120 ruler_info->constrain_mode = CONSTRAIN_MODE_OFF;
1121#endif
1122
1123 /* select and drag */
1124 if (gz->highlight_part == PART_LINE) {
1125 if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
1126 /* Add Center Point */
1127 ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
1128 inter->co_index = 1;
1129 ruler_state_set(ruler_info, RULER_STATE_DRAG);
1130
1131 /* find the factor */
1132 {
1133 float2x2 co_ss;
1134 float fac;
1135
1137 region, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP);
1139 region, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP);
1140
1141 fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]);
1142 CLAMP(fac, 0.0f, 1.0f);
1143
1144 ruler_item_pick->co[1] = blender::math::interpolate(
1145 ruler_item_pick->co[0], ruler_item_pick->co[2], fac);
1146 }
1147
1148 /* update the new location */
1151 C, depsgraph, ruler_info, ruler_item_pick, event->mval, false, false);
1152 }
1153 }
1154 else {
1155 inter->co_index = gz->highlight_part;
1156 ruler_state_set(ruler_info, RULER_STATE_DRAG);
1157
1158 /* store the initial depth */
1159 inter->drag_start_co = ruler_item_pick->co[inter->co_index];
1160 }
1161
1162 if (inter->co_index == 1) {
1163 ruler_item_pick->flag |= RULERITEM_USE_ANGLE_ACTIVE;
1164 }
1165 else {
1166 ruler_item_pick->flag &= ~RULERITEM_USE_ANGLE_ACTIVE;
1167 }
1168
1169 {
1170 /* Set Snap prev point. */
1171 float3 *prev_point;
1172 eSnapMode snap_type;
1173 if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) {
1174 prev_point = (inter->co_index != 1) ? &ruler_item_pick->co[1] : nullptr;
1175 snap_type = (inter->co_index != 1) ? ruler_item_pick->snap_type[1] : SCE_SNAP_TO_VERTEX;
1176 }
1177 else if (inter->co_index == 0) {
1178 prev_point = &ruler_item_pick->co[2];
1179 snap_type = ruler_item_pick->snap_type[2];
1180 }
1181 else {
1182 prev_point = &ruler_item_pick->co[0];
1183 snap_type = ruler_item_pick->snap_type[2];
1184 }
1185
1186 if (prev_point) {
1188 ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, *prev_point);
1190 ruler_info->snap_data.prop_snap_source_type,
1191 snap_type);
1192 }
1193 else {
1194 RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
1195 }
1196 }
1197
1198 ruler_info->item_active = ruler_item_pick;
1199
1200 /* Ensures there is a valid GPencil data in current scene. */
1202
1204}
1205
1206static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
1207{
1208 wmGizmoGroup *gzgroup = gz->parent_gzgroup;
1209 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1210
1211 if (!cancel) {
1212 if (ruler_info->state == RULER_STATE_DRAG) {
1213 RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
1215 }
1216 /* We could convert only the current gizmo, for now just re-generate. */
1217 view3d_ruler_to_gpencil(C, gzgroup);
1218 }
1219
1221
1223}
1224
1226{
1227 if (gz->highlight_part == PART_LINE) {
1228 return WM_CURSOR_CROSS;
1229 }
1230 return WM_CURSOR_NSEW_SCROLL;
1231}
1232
1234{
1235 /* identifiers */
1236 gzt->idname = "VIEW3D_GT_ruler_item";
1237
1238 /* api callbacks */
1239 gzt->draw = gizmo_ruler_draw;
1241 gzt->modal = gizmo_ruler_modal;
1243 gzt->exit = gizmo_ruler_exit;
1245
1246 gzt->struct_size = sizeof(RulerItem);
1247}
1248
1251/* -------------------------------------------------------------------- */
1255static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
1256{
1257 RulerInfo *ruler_info = (RulerInfo *)MEM_callocN(sizeof(RulerInfo), __func__);
1258
1259 wmGizmo *gizmo;
1260 {
1261 /* The gizmo snap has to be the first gizmo. */
1262 const wmGizmoType *gzt_snap;
1263 gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
1264 gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, nullptr);
1265
1267 WM_gizmo_set_color(gizmo, blender::float4(1.0f));
1268
1269 wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
1270 WM_gizmo_operator_set(gizmo, 0, ot, nullptr);
1271 }
1272
1273 if (view3d_ruler_from_gpencil(C, gzgroup)) {
1274 /* nop */
1275 }
1276
1278 wmWindow *win = CTX_wm_window(C);
1279 ScrArea *area = CTX_wm_area(C);
1280 ARegion *region = CTX_wm_region(C);
1281
1282 ruler_info->wm = wm;
1283 ruler_info->win = win;
1284 ruler_info->area = area;
1285 ruler_info->region = region;
1286 ruler_info->snap_data.gizmo = gizmo;
1287 ruler_info->snap_data.prop_prevpoint = RNA_struct_find_property(gizmo->ptr, "prev_point");
1289 "snap_source_type");
1290
1291 gzgroup->customdata = ruler_info;
1292}
1293
1307
1310/* -------------------------------------------------------------------- */
1315{
1317 if ((tref_rt == nullptr) || !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) ||
1318 CTX_wm_region_view3d(C) == nullptr)
1319 {
1320 return false;
1321 }
1322 return true;
1323}
1324
1325static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1326{
1327 ARegion *region = CTX_wm_region(C);
1328 View3D *v3d = CTX_wm_view3d(C);
1329
1331 BKE_report(op->reports, RPT_WARNING, "Gizmos hidden in this view");
1332 return OPERATOR_CANCELLED;
1333 }
1334
1335 wmGizmoMap *gzmap = region->gizmo_map;
1337
1338 if (!gizmo_ruler_check_for_operator(gzgroup)) {
1339 return OPERATOR_CANCELLED;
1340 }
1341
1342 int mval[2];
1343 WM_event_drag_start_mval(event, region, mval);
1344
1345 /* Create new line */
1346 RulerItem *ruler_item;
1347 ruler_item = ruler_item_add(gzgroup);
1348
1349 /* This is a little weak, but there is no real good way to tweak directly. */
1350 WM_gizmo_highlight_set(gzmap, &ruler_item->gz);
1352 C, "GIZMOGROUP_OT_gizmo_tweak", WM_OP_INVOKE_REGION_WIN, nullptr, event) ==
1354 {
1355 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1356 RulerInteraction *inter = static_cast<RulerInteraction *>(ruler_item->gz.interaction_data);
1358 inter->co_index = 0;
1359
1360#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
1361 /* Snap the first point added, not essential but handy. */
1362 const bool do_snap = true;
1363#else
1364 const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo);
1365#endif
1366
1367 view3d_ruler_item_mousemove(C, depsgraph, ruler_info, ruler_item, mval, false, do_snap);
1368 copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]);
1370 ruler_info->snap_data.prop_prevpoint,
1371 inter->drag_start_co);
1373 ruler_info->snap_data.prop_snap_source_type,
1374 ruler_item->snap_type[inter->co_index]);
1375
1376 copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);
1377 ruler_item->gz.highlight_part = inter->co_index = 2;
1378 }
1379 return OPERATOR_FINISHED;
1380}
1381
1383{
1384 /* identifiers */
1385 ot->name = "Ruler Add";
1386 ot->idname = "VIEW3D_OT_ruler_add";
1387 ot->description = "Add ruler";
1388
1391
1392 /* flags */
1394}
1395
1398/* -------------------------------------------------------------------- */
1402static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1403{
1404 ARegion *region = CTX_wm_region(C);
1405 View3D *v3d = CTX_wm_view3d(C);
1406
1408 BKE_report(op->reports, RPT_WARNING, "Gizmos hidden in this view");
1409 return OPERATOR_CANCELLED;
1410 }
1411
1412 wmGizmoMap *gzmap = region->gizmo_map;
1414 if (gzgroup) {
1415 if (!gizmo_ruler_check_for_operator(gzgroup)) {
1416 return OPERATOR_CANCELLED;
1417 }
1418 RulerInfo *ruler_info = static_cast<RulerInfo *>(gzgroup->customdata);
1419 if (ruler_info->item_active) {
1420 RulerItem *ruler_item = ruler_info->item_active;
1421 if ((ruler_item->flag & RULERITEM_USE_ANGLE) &&
1422 (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE))
1423 {
1425 }
1426 else {
1427 ruler_item_remove(C, gzgroup, ruler_item);
1428 }
1429
1430 /* Update the annotation layer. */
1432 view3d_ruler_to_gpencil(C, gzgroup);
1433
1435 return OPERATOR_FINISHED;
1436 }
1437 }
1438 return OPERATOR_PASS_THROUGH;
1439}
1440
1442{
1443 /* identifiers */
1444 ot->name = "Ruler Remove";
1445 ot->idname = "VIEW3D_OT_ruler_remove";
1446
1449
1450 /* flags */
1452}
1453
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)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
int BKE_scene_orientation_get_index(Scene *scene, int slot_index)
Definition scene.cc:2386
@ B_UNIT_LENGTH
Definition BKE_unit.hh:107
@ B_UNIT_ROTATION
Definition BKE_unit.hh:111
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
void BLF_size(int fontid, float size)
Definition blf.cc:426
void BLF_color3ubv(int fontid, const unsigned char rgb[3])
Definition blf.cc:459
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:778
void BLF_disable(int fontid, int option)
Definition blf.cc:321
void BLF_rotation(int fontid, float angle)
Definition blf.cc:872
void BLF_draw(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:568
int blf_mono_font
Definition blf.cc:51
void BLF_enable(int fontid, int option)
Definition blf.cc:312
@ BLF_ROTATION
Definition BLF_api.hh:361
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:371
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
MINLINE float min_ff(float a, float b)
MINLINE float min_fff(float a, float b, float c)
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:289
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])
#define RAD2DEGF(_rad)
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 BLI_snprintf(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_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags)
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:1085
Object is a sort of wrapper for general info.
@ USER_UNIT_NONE
@ SCE_ORIENT_DEFAULT
#define OBEDIT_FROM_OBACT(ob)
#define SCE_SNAP_TO_VERTEX
@ SCE_SNAP_TARGET_ALL
@ 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_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:669
short ED_transform_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 ED_transform_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])
eSnapMode ED_transform_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])
@ V3D_PROJ_TEST_CLIP_NEAR
Definition ED_view3d.hh:269
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:266
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:242
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:243
@ V3D_SNAPCURSOR_SNAP_EDIT_GEOM_CAGE
Definition ED_view3d.hh:321
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 immUniform2f(const char *name, float x, float y)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
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
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:161
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ 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
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
unsigned int U
Definition btGjkEpa3.h:78
const Depsgraph * depsgraph
int len
draw_view in_light_buf[] float
uint col
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float2 fabs(const float2 a)
static ulong state[N]
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)
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)
bool ED_gizmotypes_snap_3d_is_enabled(const wmGizmo *)
SnapObjectContext * ED_gizmotypes_snap_3d_context_ensure(Scene *scene, wmGizmo *)
void ED_gizmotypes_snap_3d_flag_set(wmGizmo *gz, int flag)
void * regiondata
void * first
float viewmat[4][4]
float winmat[4][4]
PropertyRNA * prop_snap_source_type
wmWindowManager * wm
struct RulerInfo::@541 snap_data
PropertyRNA * prop_prevpoint
RulerItem * item_active
struct RulerInfo::@540 drag_state_prev
eSnapMode snap_type[3]
ListBase spacedata
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
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
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
const char * description
Definition WM_types.hh:996
struct ReportList * reports
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)
static bool gizmo_ruler_check_for_operator(const wmGizmoGroup *gzgroup)
static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool view3d_ruler_poll(bContext *C)
static void ruler_state_set(RulerInfo *ruler_info, int state)
static const char * view3d_gzgt_ruler_id
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)
static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit, char *numstr, size_t numstr_size, int prec)
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 int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
static int gizmo_ruler_test_select(bContext *, wmGizmo *gz, const int mval[2])
@ RULERITEM_USE_ANGLE
@ RULERITEM_USE_ANGLE_ACTIVE
static RulerItem * ruler_item_add(wmGizmoGroup *gzgroup)
@ CONSTRAIN_MODE_1
@ CONSTRAIN_MODE_OFF
@ CONSTRAIN_MODE_2
static int gizmo_ruler_cursor_get(wmGizmo *gz)
#define PART_LINE
@ CONSTRAIN_AXIS_Z
@ CONSTRAIN_AXIS_Y
@ CONSTRAIN_AXIS_NONE
@ CONSTRAIN_AXIS_X
static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int gizmo_ruler_modal(bContext *C, wmGizmo *gz, const wmEvent *event, eWM_GizmoFlagTweak tweak_flag)
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)
@ RULER_STATE_DRAG
@ RULER_STATE_NORMAL
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)
#define MVAL_MAX_PX_DIST
static bool view3d_ruler_pick(wmGizmoGroup *gzgroup, RulerItem *ruler_item, const float2 mval, int *r_co_index)
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:51
@ WM_CURSOR_CROSS
Definition wm_cursors.hh:26
int xy[2]
Definition wm_draw.cc:170
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])
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
@ EVT_YKEY
@ EVT_XKEY
@ MOUSEMOVE
@ EVT_ZKEY
wmOperatorType * ot
Definition wm_files.cc:4125
wmGizmo * WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, PointerRNA *properties)
Definition wm_gizmo.cc:81
bool WM_gizmo_highlight_set(wmGizmoMap *gzmap, wmGizmo *gz)
Definition wm_gizmo.cc:401
void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
Definition wm_gizmo.cc:303
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:327
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 char *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)