Blender V5.0
transform_gizmo_3d.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
12
13#include "BLI_array_utils.h"
14#include "BLI_bounds.hh"
15#include "BLI_function_ref.hh"
16#include "BLI_listbase.h"
17#include "BLI_math_geom.h"
18#include "BLI_math_matrix.h"
19
20#include "DNA_armature_types.h"
21#include "DNA_lattice_types.h"
22#include "DNA_meta_types.h"
24
25#include "BKE_action.hh"
26#include "BKE_armature.hh"
27#include "BKE_context.hh"
28#include "BKE_crazyspace.hh"
29#include "BKE_curve.hh"
30#include "BKE_editmesh.hh"
31#include "BKE_global.hh"
32#include "BKE_grease_pencil.hh"
33#include "BKE_layer.hh"
34#include "BKE_library.hh"
35#include "BKE_object.hh"
36#include "BKE_object_types.hh"
37#include "BKE_paint.hh"
38#include "BKE_pointcache.h"
39#include "BKE_scene.hh"
40#include "BKE_screen.hh"
41
42#include "WM_api.hh"
43#include "WM_message.hh"
44
45#include "ED_armature.hh"
46#include "ED_curves.hh"
47#include "ED_gizmo_library.hh"
48#include "ED_gizmo_utils.hh"
49#include "ED_gpencil_legacy.hh"
50#include "ED_grease_pencil.hh"
51#include "ED_object.hh"
52#include "ED_particle.hh"
53#include "ED_screen.hh"
54
55#include "UI_resources.hh"
56
57#include "RNA_access.hh"
58#include "RNA_define.hh"
59
60#include "ANIM_armature.hh"
61
62/* Local module include. */
63#include "transform.hh"
64#include "transform_convert.hh"
65#include "transform_gizmo.hh"
66#include "transform_snap.hh"
67
68namespace blender::ed::transform {
69
72
74 const float twmat[4][4],
75 const float scale[3],
76 const bool ignore_hidden);
77
78/* Return codes for select, and drawing flags. */
79
80#define MAN_TRANS_X (1 << 0)
81#define MAN_TRANS_Y (1 << 1)
82#define MAN_TRANS_Z (1 << 2)
83#define MAN_TRANS_C (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
84
85#define MAN_ROT_X (1 << 3)
86#define MAN_ROT_Y (1 << 4)
87#define MAN_ROT_Z (1 << 5)
88#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)
89
90#define MAN_SCALE_X (1 << 8)
91#define MAN_SCALE_Y (1 << 9)
92#define MAN_SCALE_Z (1 << 10)
93#define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
94
95/* Threshold for testing view aligned gizmo axis. */
96static struct {
97 float min, max;
98} g_tw_axis_range[2] = {
99 /* Regular range. */
100 {0.02f, 0.1f},
101 /* Use a different range because we flip the dot product,
102 * also the view aligned planes are harder to see so hiding early is preferred. */
103 {0.175f, 0.25f},
105
106/* Axes as index. */
107enum {
112
116#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X
117#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1)
118
123 MAN_AXIS_ROT_T, /* Trackball rotation. */
124#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X
125#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1)
126
134#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X
135#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1)
136
138};
139
140/* Axis types. */
141enum {
146};
147
151
152 /* Users may change the twtype, detect changes to re-setup gizmo options. */
156
157 /* Only for view orientation. */
158 struct {
159 float viewinv_m3[3][3];
161
162 /* Only for Rotate operator. */
163 float rotation;
164
166};
167
168/* -------------------------------------------------------------------- */
171
172/* Loop over axes. */
173#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \
174 { \
175 wmGizmo *axis; \
176 int axis_idx; \
177 for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \
178 axis = gizmo_get_axis_from_index(ggd, axis_idx);
179
180#define MAN_ITER_AXES_END \
181 } \
182 } \
183 ((void)0)
184
185static wmGizmo *gizmo_get_axis_from_index(const GizmoGroup *ggd, const short axis_idx)
186{
187 BLI_assert(IN_RANGE_INCL(axis_idx, float(MAN_AXIS_TRANS_X), float(MAN_AXIS_LAST)));
188 return ggd->gizmos[axis_idx];
189}
190
191static short gizmo_get_axis_type(const int axis_idx)
192{
193 if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
194 return MAN_AXES_TRANSLATE;
195 }
196 if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
197 return MAN_AXES_ROTATE;
198 }
199 if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) {
200 return MAN_AXES_SCALE;
201 }
202 BLI_assert(0);
203 return -1;
204}
205
206static uint gizmo_orientation_axis(const int axis_idx, bool *r_is_plane)
207{
208 switch (axis_idx) {
211 if (r_is_plane) {
212 *r_is_plane = true;
213 }
215 case MAN_AXIS_TRANS_X:
216 case MAN_AXIS_ROT_X:
217 case MAN_AXIS_SCALE_X:
218 return 0;
219
222 if (r_is_plane) {
223 *r_is_plane = true;
224 }
226 case MAN_AXIS_TRANS_Y:
227 case MAN_AXIS_ROT_Y:
228 case MAN_AXIS_SCALE_Y:
229 return 1;
230
233 if (r_is_plane) {
234 *r_is_plane = true;
235 }
237 case MAN_AXIS_TRANS_Z:
238 case MAN_AXIS_ROT_Z:
239 case MAN_AXIS_SCALE_Z:
240 return 2;
241 }
242 return 3;
243}
244
245static bool gizmo_is_axis_visible(const RegionView3D *rv3d,
246 const int twtype,
247 const float idot[3],
248 const int axis_type,
249 const int axis_idx)
250{
251 if ((axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) == 0) {
252 bool is_plane = false;
253 const uint aidx_norm = gizmo_orientation_axis(axis_idx, &is_plane);
254 /* Don't draw axis perpendicular to the view. */
255 if (aidx_norm < 3) {
256 float idot_axis = idot[aidx_norm];
257 if (is_plane) {
258 idot_axis = 1.0f - idot_axis;
259 }
260 if (idot_axis < g_tw_axis_range[is_plane].min) {
261 return false;
262 }
263 }
264 }
265
266 if ((axis_type == MAN_AXES_TRANSLATE && !(twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE)) ||
267 (axis_type == MAN_AXES_ROTATE && !(twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE)) ||
268 (axis_type == MAN_AXES_SCALE && !(twtype & V3D_GIZMO_SHOW_OBJECT_SCALE)))
269 {
270 return false;
271 }
272
273 switch (axis_idx) {
274 case MAN_AXIS_TRANS_X:
275 return (rv3d->twdrawflag & MAN_TRANS_X);
276 case MAN_AXIS_TRANS_Y:
277 return (rv3d->twdrawflag & MAN_TRANS_Y);
278 case MAN_AXIS_TRANS_Z:
279 return (rv3d->twdrawflag & MAN_TRANS_Z);
280 case MAN_AXIS_TRANS_C:
281 return (rv3d->twdrawflag & MAN_TRANS_C);
282 case MAN_AXIS_ROT_X:
283 return (rv3d->twdrawflag & MAN_ROT_X);
284 case MAN_AXIS_ROT_Y:
285 return (rv3d->twdrawflag & MAN_ROT_Y);
286 case MAN_AXIS_ROT_Z:
287 return (rv3d->twdrawflag & MAN_ROT_Z);
288 case MAN_AXIS_ROT_C:
289 case MAN_AXIS_ROT_T:
290 return (rv3d->twdrawflag & MAN_ROT_C);
291 case MAN_AXIS_SCALE_X:
292 return (rv3d->twdrawflag & MAN_SCALE_X);
293 case MAN_AXIS_SCALE_Y:
294 return (rv3d->twdrawflag & MAN_SCALE_Y);
295 case MAN_AXIS_SCALE_Z:
296 return (rv3d->twdrawflag & MAN_SCALE_Z);
297 case MAN_AXIS_SCALE_C:
298 return (rv3d->twdrawflag & MAN_SCALE_C && (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0);
300 return (rv3d->twdrawflag & MAN_TRANS_X && rv3d->twdrawflag & MAN_TRANS_Y &&
301 (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0);
303 return (rv3d->twdrawflag & MAN_TRANS_Y && rv3d->twdrawflag & MAN_TRANS_Z &&
304 (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0);
306 return (rv3d->twdrawflag & MAN_TRANS_Z && rv3d->twdrawflag & MAN_TRANS_X &&
307 (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0);
309 return (rv3d->twdrawflag & MAN_SCALE_X && rv3d->twdrawflag & MAN_SCALE_Y &&
310 (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0 &&
311 (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0);
313 return (rv3d->twdrawflag & MAN_SCALE_Y && rv3d->twdrawflag & MAN_SCALE_Z &&
314 (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0 &&
315 (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0);
317 return (rv3d->twdrawflag & MAN_SCALE_Z && rv3d->twdrawflag & MAN_SCALE_X &&
318 (twtype & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) == 0 &&
319 (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) == 0);
320 }
321 return false;
322}
323
324static void gizmo_get_axis_color(const int axis_idx,
325 const float idot[3],
326 float r_col[4],
327 float r_col_hi[4])
328{
329 /* Alpha values for normal/highlighted states. */
330 const float alpha = 0.6f;
331 const float alpha_hi = 1.0f;
332 float alpha_fac;
333
334 if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
335 /* Never fade rotation rings. */
336 /* Trackball rotation axis is a special case, we only draw a slight overlay. */
337 alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.05f : 1.0f;
338 }
339 else {
340 bool is_plane = false;
341 const int axis_idx_norm = gizmo_orientation_axis(axis_idx, &is_plane);
342 /* Get alpha fac based on axis angle,
343 * to fade axis out when hiding it because it points towards view. */
344 if (axis_idx_norm < 3) {
345 const float idot_min = g_tw_axis_range[is_plane].min;
346 const float idot_max = g_tw_axis_range[is_plane].max;
347 float idot_axis = idot[axis_idx_norm];
348 if (is_plane) {
349 idot_axis = 1.0f - idot_axis;
350 }
351 alpha_fac = ((idot_axis > idot_max) ? 1.0f :
352 (idot_axis < idot_min) ? 0.0f :
353 ((idot_axis - idot_min) / (idot_max - idot_min)));
354 }
355 else {
356 alpha_fac = 1.0f;
357 }
358 }
359
360 switch (axis_idx) {
361 case MAN_AXIS_TRANS_X:
362 case MAN_AXIS_ROT_X:
363 case MAN_AXIS_SCALE_X:
367 break;
368 case MAN_AXIS_TRANS_Y:
369 case MAN_AXIS_ROT_Y:
370 case MAN_AXIS_SCALE_Y:
374 break;
375 case MAN_AXIS_TRANS_Z:
376 case MAN_AXIS_ROT_Z:
377 case MAN_AXIS_SCALE_Z:
381 break;
382 case MAN_AXIS_TRANS_C:
383 case MAN_AXIS_ROT_C:
384 case MAN_AXIS_SCALE_C:
385 case MAN_AXIS_ROT_T:
387 break;
388 }
389
390 copy_v4_v4(r_col_hi, r_col);
391
392 r_col[3] = alpha * alpha_fac;
393 r_col_hi[3] = alpha_hi * alpha_fac;
394}
395
396static void gizmo_get_axis_constraint(const int axis_idx, bool r_axis[3])
397{
398 ARRAY_SET_ITEMS(r_axis, 0, 0, 0);
399
400 switch (axis_idx) {
401 case MAN_AXIS_TRANS_X:
402 case MAN_AXIS_ROT_X:
403 case MAN_AXIS_SCALE_X:
404 r_axis[0] = true;
405 break;
406 case MAN_AXIS_TRANS_Y:
407 case MAN_AXIS_ROT_Y:
408 case MAN_AXIS_SCALE_Y:
409 r_axis[1] = true;
410 break;
411 case MAN_AXIS_TRANS_Z:
412 case MAN_AXIS_ROT_Z:
413 case MAN_AXIS_SCALE_Z:
414 r_axis[2] = true;
415 break;
418 r_axis[0] = r_axis[1] = true;
419 break;
422 r_axis[1] = r_axis[2] = true;
423 break;
426 r_axis[2] = r_axis[0] = true;
427 break;
428 default:
429 break;
430 }
431}
432
433/* **************** Preparation Stuff **************** */
434
435static void reset_tw_center(TransformBounds *tbounds)
436{
437 INIT_MINMAX(tbounds->min, tbounds->max);
438 zero_v3(tbounds->center);
439
440 for (int i = 0; i < 3; i++) {
441 tbounds->axis_min[i] = +FLT_MAX;
442 tbounds->axis_max[i] = -FLT_MAX;
443 }
444}
445
449static void calc_tw_center(TransformBounds *tbounds, const float co[3])
450{
451 minmax_v3v3_v3(tbounds->min, tbounds->max, co);
452 add_v3_v3(tbounds->center, co);
453
454 for (int i = 0; i < 3; i++) {
455 const float d = dot_v3v3(tbounds->axis[i], co);
456 tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]);
457 tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]);
458 }
459}
460
461static void protectflag_to_drawflags(short protectflag, short *drawflags)
462{
463 if (protectflag & OB_LOCK_LOCX) {
464 *drawflags &= ~MAN_TRANS_X;
465 }
466 if (protectflag & OB_LOCK_LOCY) {
467 *drawflags &= ~MAN_TRANS_Y;
468 }
469 if (protectflag & OB_LOCK_LOCZ) {
470 *drawflags &= ~MAN_TRANS_Z;
471 }
472
473 if (protectflag & OB_LOCK_ROTX) {
474 *drawflags &= ~MAN_ROT_X;
475 }
476 if (protectflag & OB_LOCK_ROTY) {
477 *drawflags &= ~MAN_ROT_Y;
478 }
479 if (protectflag & OB_LOCK_ROTZ) {
480 *drawflags &= ~MAN_ROT_Z;
481 }
482
483 if (protectflag & OB_LOCK_SCALEX) {
484 *drawflags &= ~MAN_SCALE_X;
485 }
486 if (protectflag & OB_LOCK_SCALEY) {
487 *drawflags &= ~MAN_SCALE_Y;
488 }
489 if (protectflag & OB_LOCK_SCALEZ) {
490 *drawflags &= ~MAN_SCALE_Z;
491 }
492}
493
494/* Similar to #transform_object_deform_pose_armature_get but does not check visibility. */
496{
497 BKE_view_layer_synced_ensure(scene, view_layer);
499 if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
500 /* It is assumed that when the object is in Weight Paint mode, it is not in Edit mode. So we
501 * don't need to check the #OB_MODE_EDIT flag. */
502 BLI_assert(!(ob->mode & OB_MODE_EDIT));
504 if (obpose != nullptr) {
505 ob = obpose;
506 }
507 }
508 return ob;
509}
510
524 const short orient_index,
525 const bool use_curve_handles,
526 const bool use_only_center,
527 FunctionRef<void(const float3 &)> user_fn,
528 const float (**r_mat)[4],
529 short *r_drawflags)
530{
531 const auto run_coord_with_matrix =
532 [&](const float co[3], const bool use_matrix, const float matrix[4][4]) {
533 float co_world[3];
534 if (use_matrix) {
535 mul_v3_m4v3(co_world, matrix, co);
536 co = co_world;
537 }
538 user_fn(co);
539 };
540
541 ScrArea *area = CTX_wm_area(C);
542 Scene *scene = CTX_data_scene(C);
543 /* TODO(sergey): This function is used from operator's modal() and from gizmo's refresh().
544 * Is it fine to possibly evaluate dependency graph here? */
546 ViewLayer *view_layer = CTX_data_view_layer(C);
547 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
548 int a, totsel = 0;
549
550 Object *ob = gizmo_3d_transform_space_object_get(scene, view_layer);
551
552 if (Object *obedit = OBEDIT_FROM_OBACT(ob)) {
553
554#define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) \
555 { \
556 invert_m4_m4(obedit->runtime->world_to_object.ptr(), obedit->object_to_world().ptr()); \
557 Vector<Object *> objects = BKE_view_layer_array_from_objects_in_edit_mode( \
558 scene, view_layer, CTX_wm_view3d(C)); \
559 for (Object *ob_iter : objects) { \
560 const bool use_mat_local = (ob_iter != obedit);
561
562#define FOREACH_EDIT_OBJECT_END() \
563 } \
564 } \
565 ((void)0)
566
567 ob = obedit;
568 if (obedit->type == OB_MESH) {
569 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
570 BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
571 BMesh *bm = em_iter->bm;
572
573 if (bm->totvertsel == 0) {
574 continue;
575 }
576
577 BMVert *eve;
578 BMIter iter;
579
580 float mat_local[4][4];
581 if (use_mat_local) {
583 mat_local, obedit->world_to_object().ptr(), ob_iter->object_to_world().ptr());
584 }
585
586 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
589 run_coord_with_matrix(eve->co, use_mat_local, mat_local);
590 totsel++;
591 }
592 }
593 }
594 }
596 } /* End editmesh. */
597 else if (obedit->type == OB_ARMATURE) {
598 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
599 bArmature *arm = static_cast<bArmature *>(ob_iter->data);
600
601 float mat_local[4][4];
602 if (use_mat_local) {
604 mat_local, obedit->world_to_object().ptr(), ob_iter->object_to_world().ptr());
605 }
606 LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
607 if (blender::animrig::bone_is_visible(arm, ebo)) {
608 if (ebo->flag & BONE_TIPSEL) {
609 run_coord_with_matrix(ebo->tail, use_mat_local, mat_local);
610 totsel++;
611 }
612 if ((ebo->flag & BONE_ROOTSEL) &&
613 /* Don't include same point multiple times. */
614 ((ebo->flag & BONE_CONNECTED) && (ebo->parent != nullptr) &&
615 (ebo->parent->flag & BONE_TIPSEL) &&
616 blender::animrig::bone_is_visible(arm, ebo->parent)) == 0)
617 {
618 run_coord_with_matrix(ebo->head, use_mat_local, mat_local);
619 totsel++;
620
621 if (r_drawflags) {
622 if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
623 if (ebo->flag & BONE_EDITMODE_LOCKED) {
625 r_drawflags);
626 }
627 }
628 }
629 }
630 }
631 }
632 }
634 }
635 else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
636 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
637 Curve *cu = static_cast<Curve *>(ob_iter->data);
638 BezTriple *bezt;
639 BPoint *bp;
641
642 float mat_local[4][4];
643 if (use_mat_local) {
645 mat_local, obedit->world_to_object().ptr(), ob_iter->object_to_world().ptr());
646 }
647
648 Nurb *nu = static_cast<Nurb *>(nurbs->first);
649 while (nu) {
650 if (nu->type == CU_BEZIER) {
651 bezt = nu->bezt;
652 a = nu->pntsu;
653 while (a--) {
654 /* Exceptions:
655 * - If handles are hidden then only check the center points.
656 * - If the center knot is selected then only use this as the center point.
657 */
659 if (bezt->f2 & SELECT) {
660 run_coord_with_matrix(bezt->vec[1], use_mat_local, mat_local);
661 totsel++;
662 }
663 }
664 else if (bezt->f2 & SELECT) {
665 run_coord_with_matrix(bezt->vec[1], use_mat_local, mat_local);
666 totsel++;
667 }
668 else {
669 if (bezt->f1 & SELECT) {
670 const float *co = bezt->vec[!use_curve_handles ? 1 : 0];
671 run_coord_with_matrix(co, use_mat_local, mat_local);
672 totsel++;
673 }
674 if (bezt->f3 & SELECT) {
675 const float *co = bezt->vec[!use_curve_handles ? 1 : 2];
676 run_coord_with_matrix(co, use_mat_local, mat_local);
677 totsel++;
678 }
679 }
680 bezt++;
681 }
682 }
683 else {
684 bp = nu->bp;
685 a = nu->pntsu * nu->pntsv;
686 while (a--) {
687 if (bp->f1 & SELECT) {
688 run_coord_with_matrix(bp->vec, use_mat_local, mat_local);
689 totsel++;
690 }
691 bp++;
692 }
693 }
694 nu = nu->next;
695 }
696 }
698 }
699 else if (obedit->type == OB_MBALL) {
700 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
701 MetaBall *mb = (MetaBall *)ob_iter->data;
702
703 float mat_local[4][4];
704 if (use_mat_local) {
706 mat_local, obedit->world_to_object().ptr(), ob_iter->object_to_world().ptr());
707 }
708
709 LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
710 if (ml->flag & SELECT) {
711 run_coord_with_matrix(&ml->x, use_mat_local, mat_local);
712 totsel++;
713 }
714 }
715 }
717 }
718 else if (obedit->type == OB_LATTICE) {
719 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
720 Lattice *lt = ((Lattice *)ob_iter->data)->editlatt->latt;
721 BPoint *bp = lt->def;
722 a = lt->pntsu * lt->pntsv * lt->pntsw;
723
724 float mat_local[4][4];
725 if (use_mat_local) {
727 mat_local, obedit->world_to_object().ptr(), ob_iter->object_to_world().ptr());
728 }
729
730 while (a--) {
731 if (bp->f1 & SELECT) {
732 run_coord_with_matrix(bp->vec, use_mat_local, mat_local);
733 totsel++;
734 }
735 bp++;
736 }
737 }
739 }
740 else if (obedit->type == OB_CURVES) {
741 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
742 const Curves &curves_id = *static_cast<Curves *>(ob_iter->data);
743 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
744 const bke::crazyspace::GeometryDeformation deformation =
746
747 float4x4 mat_local;
748 if (use_mat_local) {
749 mat_local = obedit->world_to_object() * ob_iter->object_to_world();
750 }
751
752 IndexMaskMemory memory;
753 const IndexMask selected_points = ed::curves::retrieve_selected_points(curves, memory);
754 const Span<float3> positions = deformation.positions;
755 totsel += selected_points.size();
756 selected_points.foreach_index([&](const int point_i) {
757 run_coord_with_matrix(positions[point_i], use_mat_local, mat_local.ptr());
758 });
759 }
761 }
762 else if (obedit->type == OB_POINTCLOUD) {
763 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
764 const PointCloud &pointcloud = *static_cast<const PointCloud *>(ob_iter->data);
765
766 float4x4 mat_local;
767 if (use_mat_local) {
768 mat_local = obedit->world_to_object() * ob_iter->object_to_world();
769 }
770
771 const bke::AttributeAccessor attributes = pointcloud.attributes();
772 const VArray selection = *attributes.lookup_or_default<bool>(
773 ".selection", bke::AttrDomain::Point, true);
774
775 IndexMaskMemory memory;
776 const IndexMask mask = IndexMask::from_bools(selection, memory);
777 const Span<float3> positions = pointcloud.positions();
778 totsel += mask.size();
779 mask.foreach_index([&](const int point) {
780 run_coord_with_matrix(positions[point], use_mat_local, mat_local.ptr());
781 });
782 }
784 }
785 else if (obedit->type == OB_GREASE_PENCIL) {
786 FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
787 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_iter->data);
788
789 float4x4 mat_local = float4x4::identity();
790 if (use_mat_local) {
791 mat_local = obedit->world_to_object() * ob_iter->object_to_world();
792 }
793
797 drawings, [&](const ed::greasepencil::MutableDrawingInfo &info) {
799
800 const bke::crazyspace::GeometryDeformation deformation =
802 *depsgraph, *ob, info.drawing);
803
804 const float4x4 layer_transform =
805 mat_local * grease_pencil.layer(info.layer_index).to_object_space(*ob_iter);
806
807 IndexMaskMemory memory;
809 memory);
810 const Span<float3> positions = deformation.positions;
811 totsel += selected_points.size();
812 selected_points.foreach_index([&](const int point_i) {
813 run_coord_with_matrix(positions[point_i], true, layer_transform.ptr());
814 });
815 });
816 }
818 }
819
820#undef FOREACH_EDIT_OBJECT_BEGIN
821#undef FOREACH_EDIT_OBJECT_END
822 }
823 else if (ob && (ob->mode & OB_MODE_POSE)) {
824 invert_m4_m4(ob->runtime->world_to_object.ptr(), ob->object_to_world().ptr());
825
826 Vector<Object *> objects = BKE_object_pose_array_get(scene, view_layer, v3d);
827
828 for (Object *ob_iter : objects) {
829 const bool use_mat_local = (ob_iter != ob);
830 /* Mislead counting bones... bah. We don't know the gizmo mode, could be mixed. */
831 const int mode = TFM_ROTATION;
832
834
835 float mat_local[4][4];
836 if (use_mat_local) {
837 mul_m4_m4m4(mat_local, ob->world_to_object().ptr(), ob_iter->object_to_world().ptr());
838 }
839
840 bArmature *arm = static_cast<bArmature *>(ob_iter->data);
841 /* Use channels to get stats. */
842 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
843 if (!(pchan->runtime.flag & POSE_RUNTIME_TRANSFORM)) {
844 continue;
845 }
846
847 float pchan_pivot[3];
848 BKE_pose_channel_transform_location(arm, pchan, pchan_pivot);
849 run_coord_with_matrix(pchan_pivot, use_mat_local, mat_local);
850 totsel++;
851
852 if (r_drawflags) {
853 /* Protect-flags apply to local space in pose mode, so only let them influence axis
854 * visibility if we show the global orientation, otherwise it's confusing. */
855 if (ELEM(orient_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) {
856 protectflag_to_drawflags(pchan->protectflag, r_drawflags);
857 }
858 }
859 }
860 }
861 }
862 else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
863 if (ob->mode & OB_MODE_SCULPT) {
864 totsel = 1;
865 run_coord_with_matrix(ob->sculpt->pivot_pos, false, ob->object_to_world().ptr());
866 }
867 }
868 else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
869 PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
870 PTCacheEditPoint *point;
871 PTCacheEditKey *ek;
872 int k;
873
874 if (edit) {
875 point = edit->points;
876 for (a = 0; a < edit->totpoint; a++, point++) {
877 if (point->flag & PEP_HIDE) {
878 continue;
879 }
880
881 for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
882 if (ek->flag & PEK_SELECT) {
883 user_fn((ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
884 totsel++;
885 }
886 }
887 }
888 }
889 }
890 else {
891
892 /* We need the one selected object, if its not active. */
893 BKE_view_layer_synced_ensure(scene, view_layer);
894 {
895 Base *base = BKE_view_layer_active_base_get(view_layer);
896 ob = base ? base->object : nullptr;
897 if (base && ((base->flag & BASE_SELECTED) == 0)) {
898 ob = nullptr;
899 }
900 }
901
903 if (!BASE_SELECTED_EDITABLE(v3d, base)) {
904 continue;
905 }
906 if (ob == nullptr) {
907 ob = base->object;
908 }
909
910 /* Get the boundbox out of the evaluated object. */
911 std::optional<std::array<float3, 8>> bb;
912 if (use_only_center == false) {
913 if (std::optional<Bounds<float3>> bounds = BKE_object_boundbox_get(base->object)) {
914 bb.emplace(bounds::corners(*bounds));
915 }
916 }
917
918 if (use_only_center || !bb) {
919 user_fn(base->object->object_to_world().location());
920 }
921 else {
922 for (uint j = 0; j < 8; j++) {
923 float co[3];
924 mul_v3_m4v3(co, base->object->object_to_world().ptr(), (*bb)[j]);
925 user_fn(co);
926 }
927 }
928 totsel++;
929 if (r_drawflags) {
930 if (orient_index == V3D_ORIENT_GLOBAL) {
931 /* Ignore scale/rotate lock flag while global orientation is active.
932 * Otherwise when object is rotated, global and local axes are misaligned, implying wrong
933 * axis as hidden/locked, see: !133286. */
934 protectflag_to_drawflags(base->object->protectflag & OB_LOCK_LOC, r_drawflags);
935 }
936 else if (ELEM(orient_index, V3D_ORIENT_LOCAL, V3D_ORIENT_GIMBAL)) {
937 protectflag_to_drawflags(base->object->protectflag, r_drawflags);
938 }
939 }
940 }
941 }
942
943 if (r_mat && ob) {
944 *r_mat = ob->object_to_world().ptr();
945 }
946
947 return totsel;
948}
949
952 TransformBounds *tbounds,
953 RegionView3D *rv3d)
954{
955 ScrArea *area = CTX_wm_area(C);
956 Scene *scene = CTX_data_scene(C);
957 ViewLayer *view_layer = CTX_data_view_layer(C);
958 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
959 int totsel = 0;
960
961 const int pivot_point = scene->toolsettings->transform_pivot_point;
962 const short orient_index = params->orientation_index ?
963 (params->orientation_index - 1) :
965
966 Object *ob = gizmo_3d_transform_space_object_get(scene, view_layer);
967 Object *obedit = OBEDIT_FROM_OBACT(ob);
968
969 tbounds->use_matrix_space = false;
970 unit_m3(tbounds->axis);
971
972 /* Global, local or normal orientation?
973 * if we could check 'totsel' now, this should be skipped with no selection. */
974 if (ob) {
975 float mat[3][3];
977 scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, mat);
978 copy_m3_m3(tbounds->axis, mat);
979 }
980
981 reset_tw_center(tbounds);
982
983 if (rv3d) {
984 /* Transform widget centroid/center. */
985 copy_m4_m3(rv3d->twmat, tbounds->axis);
986 rv3d->twdrawflag = short(0xFFFF);
987 }
988
989 if (params->use_local_axis && (ob && ob->mode & (OB_MODE_EDIT | OB_MODE_POSE))) {
990 float diff_mat[3][3];
991 copy_m3_m4(diff_mat, ob->object_to_world().ptr());
992 normalize_m3(diff_mat);
993 invert_m3(diff_mat);
994 mul_m3_m3_pre(tbounds->axis, diff_mat);
995 normalize_m3(tbounds->axis);
996
997 tbounds->use_matrix_space = true;
998 copy_m4_m4(tbounds->matrix_space, ob->object_to_world().ptr());
999 }
1000
1001 const auto gizmo_3d_tbounds_calc_fn = [&](const float3 &co) { calc_tw_center(tbounds, co); };
1002
1004 orient_index,
1005 (pivot_point != V3D_AROUND_LOCAL_ORIGINS),
1006 params->use_only_center,
1007 gizmo_3d_tbounds_calc_fn,
1008 nullptr,
1009 rv3d ? &rv3d->twdrawflag : nullptr);
1010
1011 if (totsel) {
1012 mul_v3_fl(tbounds->center, 1.0f / float(totsel)); /* Centroid! */
1013
1014 if (obedit || (ob && (ob->mode & (OB_MODE_POSE | OB_MODE_SCULPT)))) {
1015 if (ob->mode & OB_MODE_POSE) {
1016 invert_m4_m4(ob->runtime->world_to_object.ptr(), ob->object_to_world().ptr());
1017 }
1018 mul_m4_v3(ob->object_to_world().ptr(), tbounds->center);
1019 mul_m4_v3(ob->object_to_world().ptr(), tbounds->min);
1020 mul_m4_v3(ob->object_to_world().ptr(), tbounds->max);
1021 }
1022 }
1023
1024 if (rv3d) {
1025 if (totsel == 0) {
1026 unit_m4(rv3d->twmat);
1027 unit_m3(rv3d->tw_axis_matrix);
1028 zero_v3(rv3d->tw_axis_min);
1029 zero_v3(rv3d->tw_axis_max);
1030 }
1031 else {
1032 copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis);
1033 copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min);
1034 copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max);
1035 }
1036 }
1037
1038 return totsel;
1039}
1040
1041static void gizmo_get_idot(const RegionView3D *rv3d, float r_idot[3])
1042{
1043 float view_vec[3], axis_vec[3];
1044 ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
1045 for (int i = 0; i < 3; i++) {
1046 normalize_v3_v3(axis_vec, rv3d->twmat[i]);
1047 r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
1048 }
1049}
1050
1051static bool gizmo_3d_calc_pos(const bContext *C,
1052 const Scene *scene,
1053 const TransformBounds *tbounds,
1054 const short pivot_type,
1055 float r_pivot_pos[3])
1056{
1057 switch (pivot_type) {
1058 case V3D_AROUND_CURSOR:
1059 copy_v3_v3(r_pivot_pos, scene->cursor.location);
1060 return true;
1061 case V3D_AROUND_ACTIVE: {
1062 ViewLayer *view_layer = CTX_data_view_layer(C);
1063 BKE_view_layer_synced_ensure(scene, view_layer);
1064 Object *ob = BKE_view_layer_active_object_get(view_layer);
1065 if (ob != nullptr) {
1066 if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
1067 SculptSession *ss = ob->sculpt;
1068 copy_v3_v3(r_pivot_pos, ss->pivot_pos);
1069 return true;
1070 }
1071 if (object::calc_active_center(ob, false, r_pivot_pos)) {
1072 return true;
1073 }
1074 }
1075 }
1076 [[fallthrough]];
1078 TransformBounds tbounds_stack;
1079 if (tbounds == nullptr) {
1080 TransformCalcParams calc_params{};
1081 calc_params.use_only_center = true;
1082 if (calc_gizmo_stats(C, &calc_params, &tbounds_stack, nullptr)) {
1083 tbounds = &tbounds_stack;
1084 }
1085 }
1086 if (tbounds) {
1087 mid_v3_v3v3(r_pivot_pos, tbounds->min, tbounds->max);
1088 return true;
1089 }
1090 break;
1091 }
1094 if (tbounds) {
1095 copy_v3_v3(r_pivot_pos, tbounds->center);
1096 return true;
1097 }
1098
1099 float co_sum[3] = {0.0f, 0.0f, 0.0f};
1100 const auto gizmo_3d_calc_center_fn = [&](const float3 &co) { add_v3_v3(co_sum, co); };
1101 const float (*r_mat)[4] = nullptr;
1102 int totsel;
1104 0,
1105 (pivot_type != V3D_AROUND_LOCAL_ORIGINS),
1106 true,
1107 gizmo_3d_calc_center_fn,
1108 &r_mat,
1109 nullptr);
1110 if (totsel) {
1111 mul_v3_v3fl(r_pivot_pos, co_sum, 1.0f / float(totsel));
1112 if (r_mat) {
1113 mul_m4_v3(r_mat, r_pivot_pos);
1114 }
1115 return true;
1116 }
1117 }
1118 }
1119
1120 return false;
1121}
1122
1123void gizmo_prepare_mat(const bContext *C, RegionView3D *rv3d, const TransformBounds *tbounds)
1124{
1125 Scene *scene = CTX_data_scene(C);
1126 gizmo_3d_calc_pos(C, scene, tbounds, scene->toolsettings->transform_pivot_point, rv3d->twmat[3]);
1127}
1128
1133static void gizmo_line_range(const int twtype, const short axis_type, float *r_start, float *r_end)
1134{
1135 float start = 0.2f;
1136 float end = 1.0f;
1137
1138 switch (axis_type) {
1139 case MAN_AXES_TRANSLATE:
1140 if (twtype & V3D_GIZMO_SHOW_OBJECT_SCALE) {
1141 start = end - 0.125f;
1142 }
1143 if (twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
1144 /* Avoid rotate and translate gizmos overlap. */
1145 const float rotate_offset = 0.215f;
1146 start += rotate_offset;
1147 end += rotate_offset + 0.2f;
1148 }
1149 break;
1150 case MAN_AXES_SCALE:
1152 end -= 0.225f;
1153 }
1154 break;
1155 }
1156
1157 if (r_start) {
1158 *r_start = start;
1159 }
1160 if (r_end) {
1161 *r_end = end;
1162 }
1163}
1164
1166 wmMsgBus *mbus,
1167 Scene *scene,
1168 bScreen *screen,
1169 ScrArea *area,
1170 ARegion *region,
1171 void (*type_fn)(wmGizmoGroupType *))
1172{
1173 /* Subscribe to view properties. */
1174 wmMsgSubscribeValue msg_sub_value_gz_tag_refresh{};
1175 msg_sub_value_gz_tag_refresh.owner = region;
1176 msg_sub_value_gz_tag_refresh.user_data = gzgroup->parent_gzmap;
1177 msg_sub_value_gz_tag_refresh.notify = WM_gizmo_do_msg_notify_tag_refresh;
1178
1179 int orient_flag = 0;
1180 if (type_fn == VIEW3D_GGT_xform_gizmo) {
1181 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
1182 orient_flag = ggd->twtype_init;
1183 }
1184 else if (type_fn == VIEW3D_GGT_xform_cage) {
1185 orient_flag = V3D_GIZMO_SHOW_OBJECT_SCALE;
1186 /* Pass. */
1187 }
1188 else if (type_fn == VIEW3D_GGT_xform_shear) {
1189 orient_flag = V3D_GIZMO_SHOW_OBJECT_ROTATE;
1190 }
1192 orient_flag);
1193 PointerRNA orient_ref_ptr = RNA_pointer_create_discrete(
1194 &scene->id, &RNA_TransformOrientationSlot, orient_slot);
1195 const ToolSettings *ts = scene->toolsettings;
1196
1197 PointerRNA scene_ptr = RNA_id_pointer_create(&scene->id);
1198 {
1199 const PropertyRNA *props[] = {
1200 &rna_Scene_transform_orientation_slots,
1201 };
1202 for (int i = 0; i < ARRAY_SIZE(props); i++) {
1203 WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
1204 }
1205 }
1206
1207 if ((ts->transform_pivot_point == V3D_AROUND_CURSOR) || (orient_slot->type == V3D_ORIENT_CURSOR))
1208 {
1209 /* We could be more specific here, for now subscribe to any cursor change. */
1211 &scene->id, &RNA_View3DCursor, &scene->cursor);
1212 WM_msg_subscribe_rna(mbus, &cursor_ptr, nullptr, &msg_sub_value_gz_tag_refresh, __func__);
1213 }
1214
1215 {
1216 const PropertyRNA *props[] = {
1217 &rna_TransformOrientationSlot_type,
1218 &rna_TransformOrientationSlot_use,
1219 };
1220 for (int i = 0; i < ARRAY_SIZE(props); i++) {
1221 if (props[i]) {
1223 mbus, &orient_ref_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
1224 }
1225 }
1226 }
1227
1228 PointerRNA toolsettings_ptr = RNA_pointer_create_discrete(
1229 &scene->id, &RNA_ToolSettings, scene->toolsettings);
1230
1232 const PropertyRNA *props[] = {
1233 &rna_ToolSettings_transform_pivot_point,
1234 };
1235 for (int i = 0; i < ARRAY_SIZE(props); i++) {
1237 mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
1238 }
1239 }
1240
1241 {
1242 const PropertyRNA *props[] = {
1243 &rna_ToolSettings_workspace_tool_type,
1244 };
1245 for (int i = 0; i < ARRAY_SIZE(props); i++) {
1247 mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
1248 }
1249 }
1250
1252 &screen->id, &RNA_SpaceView3D, area->spacedata.first);
1253
1254 if (type_fn == VIEW3D_GGT_xform_gizmo) {
1255 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
1256 if (ggd->use_twtype_refresh) {
1257 const PropertyRNA *props[] = {
1258 &rna_SpaceView3D_show_gizmo_object_translate,
1259 &rna_SpaceView3D_show_gizmo_object_rotate,
1260 &rna_SpaceView3D_show_gizmo_object_scale,
1261 };
1262 for (int i = 0; i < ARRAY_SIZE(props); i++) {
1263 WM_msg_subscribe_rna(mbus, &view3d_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
1264 }
1265 }
1266 }
1267 else if (type_fn == VIEW3D_GGT_xform_cage) {
1268 /* Pass. */
1269 }
1270 else if (type_fn == VIEW3D_GGT_xform_shear) {
1271 /* Pass. */
1272 }
1273 else {
1274 BLI_assert(0);
1275 }
1276
1277 WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_gz_tag_refresh);
1278 WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh);
1279}
1280
1281static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region,
1282 const float axis[3],
1283 const float center_global[3],
1284 const float mval_init[2],
1285 float r_mat_basis[4][4])
1286{
1287 plane_from_point_normal_v3(r_mat_basis[2], center_global, axis);
1288 copy_v3_v3(r_mat_basis[3], center_global);
1289
1290 if (ED_view3d_win_to_3d_on_plane(region, r_mat_basis[2], mval_init, false, r_mat_basis[1])) {
1291 sub_v3_v3(r_mat_basis[1], center_global);
1292 normalize_v3(r_mat_basis[1]);
1293 cross_v3_v3v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
1294 }
1295 else {
1296 /* The plane and the mouse direction are parallel.
1297 * Calculate a matrix orthogonal to the axis. */
1298 ortho_basis_v3v3_v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
1299 }
1300
1301 r_mat_basis[0][3] = 0.0f;
1302 r_mat_basis[1][3] = 0.0f;
1303 r_mat_basis[2][3] = 0.0f;
1304 r_mat_basis[3][3] = 1.0f;
1305}
1306
1308
1309/* -------------------------------------------------------------------- */
1312
1314#define MAN_AXIS_SCALE_PLANE_SCALE 0.7f
1315
1316static void rotation_get_fn(const wmGizmo * /*gz*/, wmGizmoProperty *gz_prop, void *value)
1317{
1318 const GizmoGroup *ggd = (const GizmoGroup *)gz_prop->custom_func.user_data;
1319 *(float *)value = ggd->rotation;
1320}
1321
1322static void rotation_set_fn(const wmGizmo * /*gz*/, wmGizmoProperty *gz_prop, const void *value)
1323{
1324 GizmoGroup *ggd = (GizmoGroup *)gz_prop->custom_func.user_data;
1325 ggd->rotation = *(const float *)value;
1326}
1327
1328static void gizmo_3d_setup_default_matrix(wmGizmo *axis, const int axis_idx)
1329{
1330 float matrix[3][3];
1331
1332 switch (axis_idx) {
1333 /* Arrow. */
1334 case MAN_AXIS_TRANS_X:
1335 case MAN_AXIS_SCALE_X:
1336 case MAN_AXIS_ROT_X:
1337 copy_v3_fl3(matrix[0], 0.0f, -1.0f, 0.0f);
1338 copy_v3_fl3(matrix[1], 0.0f, 0.0f, -1.0f);
1339 copy_v3_fl3(matrix[2], 1.0f, 0.0f, 0.0f);
1340 break;
1341 case MAN_AXIS_TRANS_Y:
1342 case MAN_AXIS_SCALE_Y:
1343 case MAN_AXIS_ROT_Y:
1344 copy_v3_fl3(matrix[0], 1.0f, 0.0f, 0.0f);
1345 copy_v3_fl3(matrix[1], 0.0f, 0.0f, -1.0f);
1346 copy_v3_fl3(matrix[2], 0.0f, 1.0f, 0.0f);
1347 break;
1348 case MAN_AXIS_TRANS_Z:
1349 case MAN_AXIS_SCALE_Z:
1350 case MAN_AXIS_ROT_Z:
1351 copy_v3_fl3(matrix[0], 1.0f, 0.0f, 0.0f);
1352 copy_v3_fl3(matrix[1], 0.0f, 1.0f, 0.0f);
1353 copy_v3_fl3(matrix[2], 0.0f, 0.0f, 1.0f);
1354 break;
1355
1356 case MAN_AXIS_TRANS_XY:
1357 case MAN_AXIS_SCALE_XY:
1358 copy_v3_fl3(matrix[0], -M_SQRT1_2, M_SQRT1_2, 0.0f);
1359 copy_v3_fl3(matrix[1], 0.0f, 0.0f, 1.0f);
1360 copy_v3_fl3(matrix[2], M_SQRT1_2, M_SQRT1_2, 0.0f);
1361 break;
1362 case MAN_AXIS_TRANS_YZ:
1363 case MAN_AXIS_SCALE_YZ:
1364 copy_v3_fl3(matrix[0], 0.0f, -M_SQRT1_2, M_SQRT1_2);
1365 copy_v3_fl3(matrix[1], 1.0f, 0.0f, 0.0f);
1366 copy_v3_fl3(matrix[2], 0, M_SQRT1_2, M_SQRT1_2);
1367 break;
1368 case MAN_AXIS_SCALE_ZX:
1369 case MAN_AXIS_TRANS_ZX:
1370 copy_v3_fl3(matrix[0], M_SQRT1_2, 0.0f, -M_SQRT1_2);
1371 copy_v3_fl3(matrix[1], 0.0f, 1.0f, 0.0f);
1372 copy_v3_fl3(matrix[2], M_SQRT1_2, 0.0f, M_SQRT1_2);
1373 break;
1374
1375 case MAN_AXIS_TRANS_C:
1376 case MAN_AXIS_SCALE_C:
1377 case MAN_AXIS_ROT_C:
1378 case MAN_AXIS_ROT_T:
1379 default:
1380 return;
1381 }
1382
1383 copy_m4_m3(axis->matrix_offset, matrix);
1384}
1385
1386static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
1387{
1388 gizmo_3d_setup_default_matrix(axis, axis_idx);
1389
1390 switch (axis_idx) {
1391 /* Arrow. */
1392 case MAN_AXIS_TRANS_X:
1393 case MAN_AXIS_TRANS_Y:
1394 case MAN_AXIS_TRANS_Z:
1395 RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL);
1396 break;
1397 case MAN_AXIS_SCALE_X:
1398 case MAN_AXIS_SCALE_Y:
1399 case MAN_AXIS_SCALE_Z:
1400 RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
1401 RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_ARROW_DRAW_FLAG_STEM);
1402 break;
1403 case MAN_AXIS_TRANS_XY:
1404 case MAN_AXIS_TRANS_YZ:
1405 case MAN_AXIS_TRANS_ZX:
1406 case MAN_AXIS_SCALE_XY:
1407 case MAN_AXIS_SCALE_YZ:
1408 case MAN_AXIS_SCALE_ZX:
1409 RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_PLANE);
1410 RNA_enum_set(axis->ptr, "draw_options", 0);
1412 break;
1413
1414 /* Primitive. */
1415 case MAN_AXIS_TRANS_C:
1416 RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_CIRCLE);
1417 RNA_boolean_set(axis->ptr, "draw_inner", false);
1418 WM_gizmo_set_scale(axis, 0.2f);
1419
1420 /* Prevent axis gizmos overlapping the center point, see: #63744. */
1421 axis->select_bias = 2.0f;
1422 break;
1423 case MAN_AXIS_SCALE_C:
1425 RNA_boolean_set(axis->ptr, "draw_inner", false);
1426
1427 /* Use 6 since this is '1.2' if the main scale is 0.2. */
1428 RNA_float_set(axis->ptr, "arc_inner_factor", 6.0f);
1429 WM_gizmo_set_scale(axis, 0.2f);
1430
1431 /* Prevent axis gizmos overlapping the center point, see: #63744. */
1432 axis->select_bias = -2.0f;
1433 break;
1434
1435 /* Dial. */
1436 case MAN_AXIS_ROT_X:
1437 case MAN_AXIS_ROT_Y:
1438 case MAN_AXIS_ROT_Z:
1439 RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
1441 break;
1442 case MAN_AXIS_ROT_C:
1443 RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_NOP);
1445 WM_gizmo_set_scale(axis, 1.2f);
1446 break;
1447 case MAN_AXIS_ROT_T:
1448 RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_FILL);
1451 break;
1452 }
1453
1454 switch (axis_idx) {
1455 case MAN_AXIS_TRANS_X:
1456 case MAN_AXIS_TRANS_Y:
1457 case MAN_AXIS_TRANS_Z:
1458 case MAN_AXIS_SCALE_X:
1459 case MAN_AXIS_SCALE_Y:
1461 break;
1462 case MAN_AXIS_TRANS_XY:
1463 case MAN_AXIS_TRANS_YZ:
1464 case MAN_AXIS_TRANS_ZX:
1465 case MAN_AXIS_SCALE_XY:
1466 case MAN_AXIS_SCALE_YZ:
1467 case MAN_AXIS_SCALE_ZX:
1468 WM_gizmo_set_line_width(axis, 1.0f);
1469 break;
1470 case MAN_AXIS_ROT_X:
1471 case MAN_AXIS_ROT_Y:
1472 case MAN_AXIS_ROT_Z:
1473 /* Increased line width for better display. */
1475 break;
1476 default:
1478 break;
1479 }
1480
1481 const short axis_type = gizmo_get_axis_type(axis_idx);
1482 switch (axis_type) {
1483 case MAN_AXES_ROTATE: {
1484 RNA_float_set(axis->ptr, "incremental_angle", 0.0f);
1485 axis->select_bias = 0.0f;
1486 break;
1487 }
1488 default:
1489 break;
1490 }
1491}
1492
1493static void gizmo_3d_setup_draw_from_twtype(wmGizmo *axis, const int axis_idx, const int twtype)
1494{
1495 switch (axis_idx) {
1496 case MAN_AXIS_TRANS_X:
1497 case MAN_AXIS_TRANS_Y:
1498 case MAN_AXIS_TRANS_Z:
1499 RNA_enum_set(axis->ptr,
1500 "draw_options",
1502 0 :
1504 break;
1505 default:
1506 break;
1507 }
1508
1509 const short axis_type = gizmo_get_axis_type(axis_idx);
1510 switch (axis_idx) {
1511 case MAN_AXIS_TRANS_X:
1512 case MAN_AXIS_TRANS_Y:
1513 case MAN_AXIS_TRANS_Z:
1514 case MAN_AXIS_SCALE_X:
1515 case MAN_AXIS_SCALE_Y:
1516 case MAN_AXIS_SCALE_Z: {
1517 float start;
1518 float end;
1519 gizmo_line_range(twtype, axis_type, &start, &end);
1520 mul_v3_v3fl(axis->matrix_offset[3], axis->matrix_offset[2], start);
1521
1522 RNA_float_set(axis->ptr, "length", end - start);
1524 break;
1525 }
1526 default:
1527 break;
1528 }
1529
1530 switch (axis_type) {
1531 case MAN_AXES_ROTATE: {
1532 if ((twtype & V3D_GIZMO_SHOW_OBJECT_SCALE) && twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
1533 axis->select_bias = -2.0f;
1534 }
1535 }
1536 }
1537}
1538
1539static void gizmo_3d_setup_draw_modal(wmGizmo *axis, const int axis_idx, const int twtype)
1540{
1541 const short axis_type = gizmo_get_axis_type(axis_idx);
1542 switch (axis_idx) {
1543 case MAN_AXIS_TRANS_X:
1544 case MAN_AXIS_TRANS_Y:
1545 case MAN_AXIS_TRANS_Z:
1546 case MAN_AXIS_SCALE_X:
1547 case MAN_AXIS_SCALE_Y:
1548 case MAN_AXIS_SCALE_Z: {
1549
1550 float end, start_co[3] = {0.0f, 0.0f, 0.0f};
1551 gizmo_line_range(twtype, axis_type, nullptr, &end);
1552 RNA_float_set(axis->ptr, "length", end);
1553 RNA_enum_set(axis->ptr,
1554 "draw_options",
1558 break;
1559 }
1560 case MAN_AXIS_TRANS_XY:
1561 case MAN_AXIS_TRANS_YZ:
1562 case MAN_AXIS_TRANS_ZX:
1563 case MAN_AXIS_SCALE_XY:
1564 case MAN_AXIS_SCALE_YZ:
1565 case MAN_AXIS_SCALE_ZX:
1566 RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_ARROW_DRAW_FLAG_ORIGIN);
1567 break;
1568 case MAN_AXIS_SCALE_C:
1569 RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_CIRCLE);
1570 break;
1571 default:
1572 break;
1573 }
1574
1575 switch (axis_type) {
1576 case MAN_AXES_ROTATE: {
1577 PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options");
1578 const int dial_flag = RNA_property_enum_get(axis->ptr, prop);
1580 break;
1581 }
1582 default:
1583 break;
1584 }
1585}
1586
1588{
1589 GizmoGroup *ggd = MEM_callocN<GizmoGroup>(__func__);
1590
1591 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
1592 const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
1593 const wmGizmoType *gzt_prim = WM_gizmotype_find("GIZMO_GT_primitive_3d", true);
1594
1596 params.value_get_fn = rotation_get_fn;
1597 params.value_set_fn = rotation_set_fn;
1598 params.user_data = ggd;
1599
1600#define GIZMO_NEW_ARROW(v) \
1601 { \
1602 ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr); \
1603 } \
1604 ((void)0)
1605#define GIZMO_NEW_DIAL(v) \
1606 { \
1607 ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_dial, gzgroup, nullptr); \
1608 WM_gizmo_target_property_def_func(ggd->gizmos[v], "offset", &params); \
1609 } \
1610 ((void)0)
1611#define GIZMO_NEW_PRIM(v) \
1612 { \
1613 ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_prim, gzgroup, nullptr); \
1614 } \
1615 ((void)0)
1616
1617 /* Add/init widgets - order matters! */
1619
1621
1625
1629
1633
1634 /* Initialize screen aligned widget last here, looks better, behaves better. */
1636
1638
1642
1646
1647 MAN_ITER_AXES_BEGIN (axis, axis_idx) {
1648 gizmo_3d_setup_draw_default(axis, axis_idx);
1649 }
1651
1652 return ggd;
1653}
1654
1659 wmGizmo *widget,
1660 const wmEvent *event,
1661 eWM_GizmoFlagTweak /*tweak_flag*/)
1662{
1663 /* Avoid unnecessary updates, partially address: #55458. */
1664 if (ELEM(event->type, TIMER, INBETWEEN_MOUSEMOVE)) {
1666 }
1667
1668 ARegion *region = CTX_wm_region(C);
1669 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1670 wmGizmoGroup *gzgroup = widget->parent_gzgroup;
1671
1672 /* Recalculating the orientation has two problems.
1673 * - The matrix calculated based on the transformed selection may not match the matrix
1674 * that was set when transform started.
1675 * - Inspecting the selection for every update is expensive (for *every* redraw).
1676 *
1677 * Instead, use #transform_apply_matrix to transform `rv3d->twmat` or the final scale value
1678 * when scaling.
1679 */
1680 if (false) {
1681 TransformBounds tbounds;
1682
1683 TransformCalcParams calc_params{};
1684 calc_params.use_only_center = true;
1685 if (calc_gizmo_stats(C, &calc_params, &tbounds, rv3d)) {
1686 gizmo_prepare_mat(C, rv3d, &tbounds);
1687 LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
1688 WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
1689 }
1690 }
1691 }
1692 else {
1693 wmWindow *win = CTX_wm_window(C);
1694 wmOperator *op = nullptr;
1695 for (const wmGizmoOpElem &gzop : widget->op_data) {
1696 op = WM_operator_find_modal_by_type(win, gzop.type);
1697 if (op != nullptr) {
1698 break;
1699 }
1700 }
1701
1702 if (op != nullptr) {
1703 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
1704 const int axis_idx = BLI_array_findindex(ggd->gizmos, ARRAY_SIZE(ggd->gizmos), &widget);
1705 const short axis_type = gizmo_get_axis_type(axis_idx);
1706
1707 float twmat[4][4];
1708 float scale_buf[3];
1709 float *scale = nullptr;
1710 bool update = false;
1711 copy_m4_m4(twmat, rv3d->twmat);
1712
1713 if (axis_type == MAN_AXES_SCALE) {
1714 scale = scale_buf;
1715 transform_final_value_get(static_cast<const TransInfo *>(op->customdata), scale, 3);
1716 update = true;
1717 }
1718 else if (axis_type == MAN_AXES_ROTATE) {
1720 static_cast<const TransInfo *>(op->customdata), &ggd->rotation, 1);
1721 if (widget != ggd->gizmos[MAN_AXIS_ROT_C]) {
1722 ggd->rotation *= -1;
1723 }
1725 widget->ptr,
1726 "incremental_angle",
1727 transform_snap_increment_get(static_cast<const TransInfo *>(op->customdata)));
1728 }
1729 else if (transform_apply_matrix(static_cast<TransInfo *>(op->customdata), twmat)) {
1730 update = true;
1731 }
1732
1733 if (update) {
1734 gizmogroup_refresh_from_matrix(gzgroup, twmat, scale, true);
1736 }
1737 }
1738 }
1739
1741}
1742
1744{
1745 struct {
1746 wmOperatorType *translate, *rotate, *trackball, *resize;
1747 } ot_store = {nullptr};
1748 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
1749
1750 MAN_ITER_AXES_BEGIN (axis, axis_idx) {
1751 const short axis_type = gizmo_get_axis_type(axis_idx);
1752 bool constraint_axis[3] = {true, false, false};
1753 PointerRNA *ptr = nullptr;
1754
1755 gizmo_get_axis_constraint(axis_idx, constraint_axis);
1756
1757 /* Custom handler! */
1759
1760 gizmo_3d_setup_draw_from_twtype(axis, axis_idx, ggd->twtype);
1761
1762 switch (axis_type) {
1763 case MAN_AXES_TRANSLATE:
1764 if (ot_store.translate == nullptr) {
1765 ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
1766 }
1767 ptr = WM_gizmo_operator_set(axis, 0, ot_store.translate, nullptr);
1768 break;
1769 case MAN_AXES_ROTATE: {
1770 wmOperatorType *ot_rotate;
1771 if (axis_idx == MAN_AXIS_ROT_T) {
1772 if (ot_store.trackball == nullptr) {
1773 ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true);
1774 }
1775 ot_rotate = ot_store.trackball;
1776 }
1777 else {
1778 if (ot_store.rotate == nullptr) {
1779 ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
1780 }
1781 ot_rotate = ot_store.rotate;
1782 }
1783 ptr = WM_gizmo_operator_set(axis, 0, ot_rotate, nullptr);
1784 break;
1785 }
1786 case MAN_AXES_SCALE: {
1787 if (ot_store.resize == nullptr) {
1788 ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
1789 }
1790 ptr = WM_gizmo_operator_set(axis, 0, ot_store.resize, nullptr);
1791 break;
1792 }
1793 }
1794
1795 if (ptr) {
1796 PropertyRNA *prop;
1797 if (ELEM(true, UNPACK3(constraint_axis))) {
1798 if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) {
1799 RNA_property_boolean_set_array(ptr, prop, constraint_axis);
1800 }
1801 }
1802
1803 RNA_boolean_set(ptr, "release_confirm", true);
1804 }
1805 }
1807}
1808
1809static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
1810{
1811 GizmoGroup *ggd = gizmogroup_init(gzgroup);
1812
1813 gzgroup->customdata = ggd;
1814
1815 {
1816 ScrArea *area = CTX_wm_area(C);
1817 const bToolRef *tref = area->runtime.tool;
1818
1819 ggd->twtype = 0;
1820 if (tref && STREQ(tref->idname, "builtin.move")) {
1822 }
1823 else if (tref && STREQ(tref->idname, "builtin.rotate")) {
1825 }
1826 else if (tref && STREQ(tref->idname, "builtin.scale")) {
1828 }
1829 else if (tref && STREQ(tref->idname, "builtin.transform")) {
1832 }
1833 else {
1834 /* This is also correct logic for 'builtin.transform', no special check needed. */
1835 /* Setup all gizmos, they can be toggled via #ToolSettings::gizmo_flag. */
1838 ggd->use_twtype_refresh = true;
1839 }
1840 BLI_assert(ggd->twtype != 0);
1841 ggd->twtype_init = ggd->twtype;
1842 }
1843
1844 /* *** set properties for axes *** */
1846}
1847
1855 const int axis_idx,
1856 const int twtype,
1857 const float twmat[4][4],
1858 const float scale[3])
1859{
1860 const short axis_type = gizmo_get_axis_type(axis_idx);
1861 const int aidx_norm = gizmo_orientation_axis(axis_idx, nullptr);
1862
1863 switch (axis_idx) {
1864 case MAN_AXIS_TRANS_XY:
1865 case MAN_AXIS_TRANS_YZ:
1866 case MAN_AXIS_TRANS_ZX:
1867 case MAN_AXIS_SCALE_XY:
1868 case MAN_AXIS_SCALE_YZ:
1869 case MAN_AXIS_SCALE_ZX:
1870 copy_m4_m4(axis->matrix_basis, twmat);
1871 if (scale) {
1872 RNA_float_set(axis->ptr,
1873 "length",
1874 MAN_AXIS_SCALE_PLANE_SCALE * scale[aidx_norm == 2 ? 0 : aidx_norm + 1]);
1875 }
1876 break;
1877 case MAN_AXIS_SCALE_X:
1878 case MAN_AXIS_SCALE_Y:
1879 case MAN_AXIS_SCALE_Z:
1880 copy_m4_m4(axis->matrix_basis, twmat);
1881 if (scale) {
1882 float end;
1883 gizmo_line_range(twtype, axis_type, nullptr, &end);
1884 RNA_float_set(axis->ptr, "length", end * scale[aidx_norm]);
1885 }
1886
1887 break;
1888 case MAN_AXIS_TRANS_X:
1889 case MAN_AXIS_TRANS_Y:
1890 case MAN_AXIS_TRANS_Z:
1891 copy_m4_m4(axis->matrix_basis, twmat);
1892 break;
1893 case MAN_AXIS_SCALE_C:
1894 WM_gizmo_set_matrix_location(axis, twmat[3]);
1895 if (scale) {
1896 WM_gizmo_set_scale(axis, 0.2f * scale[0]);
1897 }
1898 break;
1899 case MAN_AXIS_ROT_X:
1900 case MAN_AXIS_ROT_Y:
1901 case MAN_AXIS_ROT_Z:
1902 copy_m4_m4(axis->matrix_basis, twmat);
1903 orthogonalize_m4(axis->matrix_basis, aidx_norm);
1904 break;
1905 case MAN_AXIS_ROT_C:
1906 case MAN_AXIS_ROT_T:
1907 default:
1908 WM_gizmo_set_matrix_location(axis, twmat[3]);
1909 break;
1910 }
1911}
1912
1914 const float twmat[4][4],
1915 const float scale[3],
1916 const bool ignore_hidden)
1917{
1918 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
1919
1920 MAN_ITER_AXES_BEGIN (axis, axis_idx) {
1921 if (ignore_hidden && axis->flag & WM_GIZMO_HIDDEN) {
1922 continue;
1923 }
1924 gizmo_refresh_from_matrix(axis, axis_idx, ggd->twtype, twmat, scale);
1925 }
1927}
1928
1930{
1931 if (WM_gizmo_group_is_modal(gzgroup)) {
1932 return;
1933 }
1934
1935 ARegion *region = CTX_wm_region(C);
1936 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
1937 Scene *scene = CTX_data_scene(C);
1938 ScrArea *area = CTX_wm_area(C);
1939 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
1940 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1941 TransformBounds tbounds;
1942
1943 if (ggd->use_twtype_refresh) {
1944 ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
1945 if (ggd->twtype != ggd->twtype_prev) {
1946 ggd->twtype_prev = ggd->twtype;
1948 }
1949 }
1950
1951 const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init);
1952
1953 /* Skip, we don't draw anything anyway. */
1954 TransformCalcParams calc_params{};
1955 calc_params.use_only_center = true;
1956 calc_params.orientation_index = orient_index + 1;
1957 if ((ggd->all_hidden = (calc_gizmo_stats(C, &calc_params, &tbounds, rv3d) == 0))) {
1958 return;
1959 }
1960
1962 C, scene, &tbounds, scene->toolsettings->transform_pivot_point, rv3d->twmat[3]);
1963
1964 gizmogroup_refresh_from_matrix(gzgroup, rv3d->twmat, nullptr, false);
1965}
1966
1968 wmGizmoGroup *gzgroup,
1969 wmMsgBus *mbus)
1970{
1971 Scene *scene = CTX_data_scene(C);
1972 bScreen *screen = CTX_wm_screen(C);
1973 ScrArea *area = CTX_wm_area(C);
1974 ARegion *region = CTX_wm_region(C);
1976 gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_gizmo);
1977}
1978
1980{
1981 MAN_ITER_AXES_BEGIN (axis, axis_idx) {
1983 }
1985}
1986
1988{
1989 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
1990 // ScrArea *area = CTX_wm_area(C);
1991 ARegion *region = CTX_wm_region(C);
1992 // View3D *v3d =static_cast< View3D *> (area->spacedata.first);
1993 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1994 float viewinv_m3[3][3];
1995 copy_m3_m4(viewinv_m3, rv3d->viewinv);
1996 float idot[3];
1997
1998 /* Re-calculate hidden unless modal. */
1999 const bool is_modal = WM_gizmo_group_is_modal(gzgroup);
2000
2001 /* When looking through a selected camera, the gizmo can be at the
2002 * exact same position as the view, skip so we don't break selection. */
2003 if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) {
2004 if (!is_modal) {
2006 }
2007 return;
2008 }
2009 gizmo_get_idot(rv3d, idot);
2010
2011 /* *** set properties for axes *** */
2012 MAN_ITER_AXES_BEGIN (axis, axis_idx) {
2013 if (is_modal) {
2014 if (axis->flag & WM_GIZMO_HIDDEN) {
2015 continue;
2016 }
2017 }
2018 else {
2019 const short axis_type = gizmo_get_axis_type(axis_idx);
2020 if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) {
2021 /* XXX maybe unset _HIDDEN flag on redraw? */
2022 WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
2023 }
2024 else {
2026 continue;
2027 }
2028
2029 /* Align to view. */
2030 switch (axis_idx) {
2031 case MAN_AXIS_TRANS_C:
2032 case MAN_AXIS_ROT_C:
2033 case MAN_AXIS_SCALE_C:
2034 case MAN_AXIS_ROT_T:
2036 break;
2037 }
2038 }
2039
2040 float color[4], color_hi[4];
2041 gizmo_get_axis_color(axis_idx, idot, color, color_hi);
2043 WM_gizmo_set_color_highlight(axis, color_hi);
2044 }
2046
2047 /* Refresh handled above when using view orientation. */
2048 if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) {
2049 {
2050 Scene *scene = CTX_data_scene(C);
2052 scene, ggd->twtype_init);
2053 switch (orient_slot->type) {
2054 case V3D_ORIENT_VIEW: {
2055 WIDGETGROUP_gizmo_refresh(C, gzgroup);
2056 break;
2057 }
2058 }
2059 }
2060 copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv);
2061 }
2062}
2063
2065 const ARegion *region,
2066 const int axis_idx_active,
2067 const float mval[2])
2068{
2069 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
2070 const RegionView3D *rv3d = static_cast<const RegionView3D *>(region->regiondata);
2071
2072 wmGizmo *axis_active = ggd->gizmos[axis_idx_active];
2073
2074 const short axis_active_type = gizmo_get_axis_type(axis_idx_active);
2075
2076 /* Display only the active gizmo. */
2078 WM_gizmo_set_flag(axis_active, WM_GIZMO_HIDDEN, false);
2079 gizmo_refresh_from_matrix(axis_active, axis_idx_active, ggd->twtype, rv3d->twmat, nullptr);
2080
2083 }
2084
2085 gizmo_3d_setup_draw_modal(axis_active, axis_idx_active, ggd->twtype);
2086
2087 if (axis_active_type == MAN_AXES_TRANSLATE) {
2088 /* Arrows are used for visual reference, so keep all visible. */
2089 for (int axis_idx = MAN_AXIS_TRANS_X; axis_idx <= MAN_AXIS_TRANS_Z; axis_idx++) {
2090 if (axis_idx == axis_idx_active) {
2091 continue;
2092 }
2093 wmGizmo *axis = ggd->gizmos[axis_idx];
2094 WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
2095 gizmo_refresh_from_matrix(axis, axis_idx, ggd->twtype, rv3d->twmat, nullptr);
2096 gizmo_3d_setup_draw_default(axis, axis_idx);
2097 gizmo_3d_setup_draw_from_twtype(axis, axis_idx, ggd->twtype);
2098 RNA_enum_set(axis->ptr, "draw_options", ED_GIZMO_ARROW_DRAW_FLAG_STEM);
2099 }
2100 }
2101 else if (axis_active_type == MAN_AXES_ROTATE && axis_idx_active != MAN_AXIS_ROT_T) {
2102 float mat[3][3];
2103 mul_m3_m4m4(mat, axis_active->matrix_basis, axis_active->matrix_offset);
2105 region, mat[2], axis_active->matrix_basis[3], mval, axis_active->matrix_offset);
2106
2107 copy_m3_m4(mat, axis_active->matrix_basis);
2108 invert_m3(mat);
2109 mul_m4_m3m4(axis_active->matrix_offset, mat, axis_active->matrix_offset);
2110 zero_v3(axis_active->matrix_offset[3]);
2111 }
2112}
2113
2115 wmGizmoGroup *gzgroup,
2116 wmGizmo *gz,
2117 const wmEvent *event)
2118{
2119 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup->customdata);
2120 const int axis_idx = BLI_array_findindex(ggd->gizmos, ARRAY_SIZE(ggd->gizmos), &gz);
2121
2122 const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
2123 gizmo_3d_draw_invoke(gzgroup, CTX_wm_region(C), axis_idx, mval);
2124
2125 /* Support gizmo specific orientation. */
2126 if (gz != ggd->gizmos[MAN_AXIS_ROT_T]) {
2127 Scene *scene = CTX_data_scene(C);
2128 wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
2129 PointerRNA *ptr = &gzop->ptr;
2130 PropertyRNA *prop_orient_type = RNA_struct_find_property(ptr, "orient_type");
2132 scene, ggd->twtype_init);
2133 if ((gz == ggd->gizmos[MAN_AXIS_ROT_C]) ||
2134 (orient_slot == &scene->orientation_slots[SCE_ORIENT_DEFAULT]))
2135 {
2136 /* #MAN_AXIS_ROT_C always uses the #V3D_ORIENT_VIEW orientation,
2137 * optionally we could set this orientation instead of unset the property. */
2138 RNA_property_unset(ptr, prop_orient_type);
2139 }
2140 else {
2141 /* TODO: API function. */
2142 int index = BKE_scene_orientation_slot_get_index(orient_slot);
2143 RNA_property_enum_set(ptr, prop_orient_type, index);
2144 }
2145 }
2146
2147 /* Support shift click to constrain axis. */
2148 int axis = -1;
2149 switch (axis_idx) {
2150 case MAN_AXIS_TRANS_X:
2151 case MAN_AXIS_TRANS_Y:
2152 case MAN_AXIS_TRANS_Z:
2153 axis = axis_idx - MAN_AXIS_TRANS_X;
2154 break;
2155 case MAN_AXIS_SCALE_X:
2156 case MAN_AXIS_SCALE_Y:
2157 case MAN_AXIS_SCALE_Z:
2158 axis = axis_idx - MAN_AXIS_SCALE_X;
2159 break;
2160 }
2161
2162 if (axis != -1) {
2163 /* Swap single axis for two-axis constraint. */
2164 const bool flip = (event->modifier & KM_SHIFT) != 0;
2165 BLI_assert(axis_idx != -1);
2166 const short axis_type = gizmo_get_axis_type(axis_idx);
2167 if (axis_type != MAN_AXES_ROTATE) {
2168 wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
2169 PointerRNA *ptr = &gzop->ptr;
2170 PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
2171 if (prop_constraint_axis) {
2172 bool constraint[3] = {false};
2173 constraint[axis] = true;
2174 if (flip) {
2175 for (int i = 0; i < ARRAY_SIZE(constraint); i++) {
2176 constraint[i] = !constraint[i];
2177 }
2178 }
2179 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
2180 }
2181 }
2182 }
2183}
2184
2186{
2187 if (v3d->gizmo_flag & V3D_GIZMO_HIDE) {
2188 return false;
2189 }
2190 if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) {
2191 return false;
2192 }
2193 return true;
2194}
2195
2197{
2198 ScrArea *area = CTX_wm_area(C);
2199 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
2201 return false;
2202 }
2203
2204 const bToolRef *tref = area->runtime.tool;
2206 return false;
2207 }
2210 {
2211 return false;
2212 }
2213
2214 /* Don't show if the tool has a gizmo. */
2215 if (tref && tref->runtime && tref->runtime->gizmo_group[0]) {
2216 return false;
2217 }
2218 return true;
2219}
2220
2222{
2224 return false;
2225 }
2226
2227 ScrArea *area = CTX_wm_area(C);
2228 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
2230 return false;
2231 }
2232
2233 if (v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) {
2234 return false;
2235 }
2236
2237 return true;
2238}
2239
2240/* Expose as multiple gizmos so tools use one, persistent context another.
2241 * Needed because they use different options which isn't so simple to dynamically update. */
2242
2244{
2245 gzgt->name = "3D View: Transform Gizmo";
2246 gzgt->idname = "VIEW3D_GGT_xform_gizmo";
2247
2250
2253
2261
2262 static const EnumPropertyItem rna_enum_gizmo_items[] = {
2263 {V3D_GIZMO_SHOW_OBJECT_TRANSLATE, "TRANSLATE", 0, "Move", ""},
2264 {V3D_GIZMO_SHOW_OBJECT_ROTATE, "ROTATE", 0, "Rotate", ""},
2265 {V3D_GIZMO_SHOW_OBJECT_SCALE, "SCALE", 0, "Scale", ""},
2266 {0, "NONE", 0, "None", ""},
2267 {0, nullptr, 0, nullptr, nullptr},
2268 };
2269 RNA_def_enum(gzgt->srna,
2270 "drag_action",
2271 rna_enum_gizmo_items,
2273 "Drag Action",
2274 "");
2275
2276 g_GGT_xform_gizmo = gzgt;
2277}
2278
2297
2299
2301{
2302 wmGizmoMap *gizmo_map = t->region->runtime->gizmo_map;
2303 if (gizmo_map == nullptr) {
2304 BLI_assert_msg(false, "#T_NO_GIZMO should already be set to return early before.");
2305 return nullptr;
2306 }
2307
2308 wmGizmo *gizmo_modal_current = WM_gizmomap_get_modal(gizmo_map);
2309 if (gizmo_modal_current) {
2310 wmGizmoGroup *gzgroup = gizmo_modal_current->parent_gzgroup;
2311 /* Check #wmGizmoGroup::customdata to make sure the GizmoGroup has been initialized. */
2312 if (gzgroup->customdata && ELEM(gzgroup->type, g_GGT_xform_gizmo, g_GGT_xform_gizmo_context)) {
2313 return gzgroup;
2314 }
2315 }
2316 else {
2317 /* See #WM_gizmomap_group_find_ptr. */
2318 LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gizmo_map)) {
2320 /* Choose the one that has been initialized. */
2321 if (gzgroup->customdata) {
2322 return gzgroup;
2323 }
2324 }
2325 }
2326 }
2327
2328 return nullptr;
2329}
2330
2332{
2333 wmGizmo *gizmo_modal_current = t->region && t->region->runtime->gizmo_map ?
2334 WM_gizmomap_get_modal(t->region->runtime->gizmo_map) :
2335 nullptr;
2336 if (!gizmo_modal_current || !ELEM(gizmo_modal_current->parent_gzgroup->type,
2339 {
2340 t->flag |= T_NO_GIZMO;
2341 }
2342}
2343
2345{
2346 if (t->flag & T_NO_GIZMO) {
2347 return;
2348 }
2349
2350 wmGizmoGroup *gzgroup_xform = gizmogroup_xform_find(t);
2351 if (gzgroup_xform == nullptr) {
2352 return;
2353 }
2354
2355 int axis_idx = -1;
2356 if (t->mode == TFM_TRACKBALL) {
2357 /* Pass. Do not display gizmo. */
2358 }
2360 const int axis_map[3][7] = {
2382 };
2383
2385 /* Assert mode values. */
2387 /* Assert constrain values. */
2388 (CON_AXIS0 == (1 << 1)) && (CON_AXIS1 == (1 << 2)) && (CON_AXIS2 == (1 << 3))),
2389 "");
2390
2391 const int trans_mode = t->mode - TFM_TRANSLATION;
2392 int con_mode = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) >> 1) - 1;
2393 if (t->con.mode & CON_APPLY) {
2394 con_mode = ((t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) >> 1) - 1;
2395 }
2396
2397 axis_idx = axis_map[trans_mode][con_mode];
2398 }
2399
2400 wmGizmo *gizmo_modal_current = WM_gizmomap_get_modal(t->region->runtime->gizmo_map);
2401 if (axis_idx != -1) {
2402 RegionView3D *rv3d = static_cast<RegionView3D *>(t->region->regiondata);
2403 float (*mat_cmp)[3] = t->orient[t->orient_curr != O_DEFAULT ? t->orient_curr : O_SCENE].matrix;
2404
2405 bool update_orientation = !(equals_v3v3(rv3d->twmat[0], mat_cmp[0]) &&
2406 equals_v3v3(rv3d->twmat[1], mat_cmp[1]) &&
2407 equals_v3v3(rv3d->twmat[2], mat_cmp[2]));
2408
2409 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup_xform->customdata);
2410 wmGizmo *gizmo_expected = ggd->gizmos[axis_idx];
2411 if (update_orientation || gizmo_modal_current != gizmo_expected) {
2412 if (update_orientation) {
2413 copy_m4_m3(rv3d->twmat, mat_cmp);
2414 copy_v3_v3(rv3d->twmat[3], t->center_global);
2415 }
2416
2417 wmEvent event = {nullptr};
2418
2419 /* Set the initial mouse value. Used for rotation gizmos. */
2420 copy_v2_v2_int(event.mval, int2(t->mouse.imval));
2421
2422 /* We need to update the position of the gizmo before invoking otherwise
2423 * #wmGizmo::scale_final could be calculated wrong. */
2424 gizmo_refresh_from_matrix(gizmo_expected, axis_idx, ggd->twtype, rv3d->twmat, nullptr);
2425
2426 BLI_assert_msg(!gizmo_modal_current || gizmo_modal_current->highlight_part == 0,
2427 "Avoid changing the highlight part");
2428 gizmo_expected->highlight_part = 0;
2430 t->region->runtime->gizmo_map, t->context, gizmo_expected, &event);
2431 WM_gizmo_highlight_set(t->region->runtime->gizmo_map, gizmo_expected);
2432 }
2433 }
2434 else if (gizmo_modal_current) {
2435 WM_gizmo_modal_set_while_modal(t->region->runtime->gizmo_map, t->context, nullptr, nullptr);
2436 }
2437}
2438
2440{
2441 if (t->flag & T_NO_GIZMO) {
2442 return;
2443 }
2444
2445 wmGizmoGroup *gzgroup_xform = gizmogroup_xform_find(t);
2446 if (gzgroup_xform == nullptr) {
2447 return;
2448 }
2449
2450 GizmoGroup *ggd = static_cast<GizmoGroup *>(gzgroup_xform->customdata);
2451
2452 /* #wmGizmoGroup::draw_prepare will handle the rest. */
2453 MAN_ITER_AXES_BEGIN (axis, axis_idx) {
2454 gizmo_3d_setup_draw_default(axis, axis_idx);
2455 gizmo_3d_setup_draw_from_twtype(axis, axis_idx, ggd->twtype);
2456 }
2458}
2459
2460bool calc_pivot_pos(const bContext *C, const short pivot_type, float r_pivot_pos[3])
2461{
2462 Scene *scene = CTX_data_scene(C);
2463 return gizmo_3d_calc_pos(C, scene, nullptr, pivot_type, r_pivot_pos);
2464}
2465
2466} // namespace blender::ed::transform
Functions to deal with Armatures.
Blender kernel action and pose functionality.
void BKE_pose_channel_transform_location(const bArmature *arm, const bPoseChannel *pose_bone, float r_pose_space_pivot[3])
Depsgraph * CTX_data_expect_evaluated_depsgraph(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition curve.cc:419
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
@ G_TRANSFORM_OBJ
@ G_TRANSFORM_EDIT
Low-level operations for grease pencil.
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_active_base_get(ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
General operations, lookup, etc. for blender objects.
Object * BKE_object_pose_armature_get(Object *ob)
std::optional< blender::Bounds< blender::float3 > > BKE_object_boundbox_get(const Object *ob)
blender::Vector< Object * > BKE_object_pose_array_get(const Scene *scene, ViewLayer *view_layer, View3D *v3d)
#define PEP_HIDE
#define PEK_SELECT
#define PEK_USE_WCO
TransformOrientationSlot * BKE_scene_orientation_slot_get_from_flag(Scene *scene, int flag)
Definition scene.cc:2408
int BKE_scene_orientation_slot_get_index(const TransformOrientationSlot *orient_slot)
Definition scene.cc:2432
int BKE_scene_orientation_get_index_from_flag(Scene *scene, int flag)
Definition scene.cc:2445
int BKE_scene_orientation_get_index(Scene *scene, int slot_index)
Definition scene.cc:2439
Generic array manipulation API.
#define BLI_array_findindex(arr, arr_len, p)
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define ATTR_FALLTHROUGH
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define M_SQRT1_2
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:217
void orthogonalize_m4(float R[4][4], int axis)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m3_m3_pre(float R[3][3], const float A[3][3])
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void unit_m3(float m[3][3])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void normalize_m3(float R[3][3]) ATTR_NONNULL()
bool equals_m3m3(const float mat1[3][3], const float mat2[3][3])
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4])
bool invert_m3(float mat[3][3])
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4])
void unit_m4(float m[4][4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
unsigned int uint
#define INIT_MINMAX(min, max)
#define ARRAY_SIZE(arr)
#define ARRAY_SET_ITEMS(...)
#define UNPACK3(a)
#define ELEM(...)
#define IN_RANGE_INCL(a, b, c)
#define STREQ(a, b)
@ POSE_RUNTIME_TRANSFORM
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_EDITMODE_LOCKED
@ BONE_TIPSEL
@ BONE_CONNECTED
@ CU_BEZIER
#define OB_MODE_ALL_PAINT
@ OB_MODE_PARTICLE_EDIT
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_SCULPT
@ OB_MODE_POSE
#define OB_MODE_ALL_SCULPT
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES_LEGACY
@ OB_CURVES
@ OB_LOCK_ROTZ
@ OB_LOCK_ROT
@ OB_LOCK_SCALEZ
@ OB_LOCK_ROTX
@ OB_LOCK_SCALEX
@ OB_LOCK_LOCY
@ OB_LOCK_LOCZ
@ OB_LOCK_ROTY
@ OB_LOCK_SCALEY
@ OB_LOCK_LOC
@ OB_LOCK_LOCX
@ OB_LOCK_SCALE
#define BASE_SELECTED(v3d, base)
#define BASE_SELECTED_EDITABLE(v3d, base)
@ SCE_ORIENT_DEFAULT
#define OBEDIT_FROM_OBACT(ob)
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
@ V3D_GIZMO_HIDE_TOOL
@ V3D_GIZMO_HIDE
@ V3D_GIZMO_HIDE_CONTEXT
@ V3D_GIZMO_SHOW_OBJECT_ROTATE
@ V3D_GIZMO_SHOW_OBJECT_SCALE
@ V3D_GIZMO_SHOW_OBJECT_TRANSLATE
@ V3D_AROUND_ACTIVE
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CURSOR
@ V3D_AROUND_CENTER_MEDIAN
@ V3D_AROUND_LOCAL_ORIGINS
@ V3D_ORIENT_GLOBAL
@ V3D_ORIENT_LOCAL
@ V3D_ORIENT_VIEW
@ V3D_ORIENT_CURSOR
@ V3D_ORIENT_GIMBAL
@ CURVE_HANDLE_NONE
@ OPERATOR_RUNNING_MODAL
@ ED_GIZMO_DIAL_DRAW_FLAG_FILL
@ ED_GIZMO_DIAL_DRAW_FLAG_NOP
@ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE
@ ED_GIZMO_DIAL_DRAW_FLAG_CLIP
@ ED_GIZMO_ARROW_DRAW_FLAG_ORIGIN
@ ED_GIZMO_ARROW_DRAW_FLAG_STEM
@ ED_GIZMO_PRIMITIVE_STYLE_ANNULUS
@ ED_GIZMO_PRIMITIVE_STYLE_CIRCLE
@ ED_GIZMO_ARROW_STYLE_PLANE
@ ED_GIZMO_ARROW_STYLE_BOX
@ ED_GIZMO_ARROW_STYLE_NORMAL
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
PTCacheEdit * PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:654
void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float r_out[3])
float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
bool ED_view3d_win_to_3d_on_plane(const ARegion *region, const float plane[4], const float mval[2], bool do_clip, float r_out[3])
#define Window
#define C
Definition RandGen.cpp:29
@ TH_GIZMO_VIEW_ALIGN
@ TH_AXIS_Y
@ TH_AXIS_X
@ TH_AXIS_Z
void UI_GetThemeColor4fv(int colorid, float col[4])
eWM_GizmoFlagTweak
Gizmo tweak flag. Bit-flag passed to gizmo while tweaking.
@ WM_GIZMO_HIDDEN
@ WM_GIZMO_DRAW_VALUE
@ WM_GIZMO_DRAW_HOVER
@ WM_GIZMO_DRAW_OFFSET_SCALE
@ WM_GIZMO_SELECT_BACKGROUND
@ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP
@ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK
@ WM_GIZMOGROUPTYPE_3D
@ WM_GIZMOGROUPTYPE_PERSISTENT
@ KM_SHIFT
Definition WM_types.hh:278
volatile int lock
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_VERTS_OF_MESH
BMesh * bm
BPy_StructRNA * depsgraph
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
const bke::CurvesGeometry & strokes() const
void foreach_index(Fn &&fn) const
nullptr float
#define SELECT
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define G(x, y, z)
bool bone_is_visible(const bArmature *armature, const Bone *bone)
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval, const Object &ob_orig, const bke::greasepencil::Drawing &drawing_orig)
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig)
std::array< VecBase< T, 3 >, 8 > corners(const Bounds< VecBase< T, 3 > > &bounds)
IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
Vector< MutableDrawingInfo > retrieve_editable_drawings(const Scene &scene, GreasePencil &grease_pencil)
bool calc_active_center(Object *ob, bool select_only, float r_center[3])
static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, wmMsgBus *mbus, Scene *scene, bScreen *screen, ScrArea *area, ARegion *region, void(*type_fn)(wmGizmoGroupType *))
static void gizmo_get_axis_color(const int axis_idx, const float idot[3], float r_col[4], float r_col_hi[4])
static bool WIDGETGROUP_gizmo_poll_tool(const bContext *C, wmGizmoGroupType *gzgt)
static void protectflag_to_drawflags(short protectflag, short *drawflags)
static wmGizmoGroup * gizmogroup_xform_find(TransInfo *t)
static void rotation_get_fn(const wmGizmo *, wmGizmoProperty *gz_prop, void *value)
static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void calc_tw_center(TransformBounds *tbounds, const float co[3])
static wmGizmo * gizmo_get_axis_from_index(const GizmoGroup *ggd, const short axis_idx)
void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
static Object * gizmo_3d_transform_space_object_get(Scene *scene, ViewLayer *view_layer)
static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
static void rotation_set_fn(const wmGizmo *, wmGizmoProperty *gz_prop, const void *value)
static void gizmo_get_idot(const RegionView3D *rv3d, float r_idot[3])
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, wmMsgBus *mbus)
static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
static struct blender::ed::transform::@235063353046371357344023025232136250272145372042 g_tw_axis_range[2]
static void gizmo_get_axis_constraint(const int axis_idx, bool r_axis[3])
static void gizmogroup_refresh_from_matrix(wmGizmoGroup *gzgroup, const float twmat[4][4], const float scale[3], const bool ignore_hidden)
void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
void gizmo_prepare_mat(const bContext *C, RegionView3D *rv3d, const TransformBounds *tbounds)
static void gizmo_line_range(const int twtype, const short axis_type, float *r_start, float *r_end)
static wmGizmoGroupType * g_GGT_xform_gizmo_context
static GizmoGroup * gizmogroup_init(wmGizmoGroup *gzgroup)
void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
void transform_gizmo_3d_model_from_constraint_and_mode_init(TransInfo *t)
void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
static void gizmo_refresh_from_matrix(wmGizmo *axis, const int axis_idx, const int twtype, const float twmat[4][4], const float scale[3])
static bool WIDGETGROUP_gizmo_poll_context(const bContext *C, wmGizmoGroupType *)
static void gizmo_3d_setup_draw_from_twtype(wmGizmo *axis, const int axis_idx, const int twtype)
static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region, const float axis[3], const float center_global[3], const float mval_init[2], float r_mat_basis[4][4])
static wmOperatorStatus gizmo_modal(bContext *C, wmGizmo *widget, const wmEvent *event, eWM_GizmoFlagTweak)
static void gizmogroup_hide_all(GizmoGroup *ggd)
void transform_convert_pose_transflags_update(Object *ob, int mode, short around)
static void gizmo_3d_setup_default_matrix(wmGizmo *axis, const int axis_idx)
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t)
bool calc_pivot_pos(const bContext *C, const short pivot_type, float r_pivot_pos[3])
static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C, wmGizmoGroup *gzgroup, wmGizmo *gz, const wmEvent *event)
static bool gizmo_3d_calc_pos(const bContext *C, const Scene *scene, const TransformBounds *tbounds, const short pivot_type, float r_pivot_pos[3])
static void gizmo_3d_draw_invoke(wmGizmoGroup *gzgroup, const ARegion *region, const int axis_idx_active, const float mval[2])
static void gizmo_3d_setup_draw_modal(wmGizmo *axis, const int axis_idx, const int twtype)
void transform_final_value_get(const TransInfo *t, float *value, const int value_num)
static short gizmo_get_axis_type(const int axis_idx)
static void reset_tw_center(TransformBounds *tbounds)
static int gizmo_3d_foreach_selected(const bContext *C, const short orient_index, const bool use_curve_handles, const bool use_only_center, FunctionRef< void(const float3 &)> user_fn, const float(**r_mat)[4], short *r_drawflags)
static wmGizmoGroupType * g_GGT_xform_gizmo
static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
static bool gizmo_is_axis_visible(const RegionView3D *rv3d, const int twtype, const float idot[3], const int axis_type, const int axis_idx)
bool transform_apply_matrix(TransInfo *t, float mat[4][4])
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])
void transform_gizmo_3d_model_from_constraint_and_mode_restore(TransInfo *t)
int calc_gizmo_stats(const bContext *C, const TransformCalcParams *params, TransformBounds *tbounds, RegionView3D *rv3d)
float transform_snap_increment_get(const TransInfo *t)
static uint gizmo_orientation_axis(const int axis_idx, bool *r_is_plane)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:56
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
static void update(bNodeTree *ntree)
static void rotate(float new_co[3], float a, const float ax[3], const float co[3])
#define fabsf
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
PointerRNA RNA_id_pointer_create(ID *id)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
#define FLT_MAX
Definition stdcycles.h:14
void * regiondata
ARegionRuntimeHandle * runtime
float co[3]
uint8_t f1
float vec[4]
short flag
struct Object * object
float vec[3][3]
CurvesGeometry geometry
struct Lattice * latt
struct EditLatt * editlatt
struct BPoint * def
void * first
ListBase * editelems
struct Nurb * next
short type
BezTriple * bezt
BPoint * bp
ObjectRuntimeHandle * runtime
struct SculptSession * sculpt
struct PTCacheEditKey * keys
PTCacheEditPoint * points
float tw_axis_matrix[3][3]
float tw_axis_min[3]
float tw_axis_max[3]
float twmat[4][4]
float viewinv[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
TransformOrientationSlot orientation_slots[4]
struct bToolRef * tool
ListBase spacedata
ScrArea_Runtime runtime
blender::float3 pivot_pos
Definition BKE_paint.hh:466
View3DOverlay overlay
char gizmo_show_object
ListBase * edbo
bToolRef_Runtime * runtime
const c_style_mat & ptr() const
struct blender::ed::transform::GizmoGroup::@203047020261350113033344047363134330146255114316 prev
struct blender::ed::transform::TransInfo::@342160341045112220003361360177273117120157367076 orient[3]
wmEventType type
Definition WM_types.hh:757
int mval[2]
Definition WM_types.hh:763
wmGizmoGroupFnSetupKeymap setup_keymap
wmGizmoGroupFnMsgBusSubscribe message_subscribe
wmGizmoGroupFnRefresh refresh
wmGizmoGroupFnInit setup
const char * idname
wmGizmoGroupFnInvokePrepare invoke_prepare
wmGizmoMapType_Params gzmap_params
eWM_GizmoFlagGroupTypeFlag flag
wmGizmoGroupFnPoll poll
wmGizmoGroupFnDrawPrepare draw_prepare
wmGizmoMap * parent_gzmap
wmGizmoGroupType * type
wmOperatorType * type
struct wmGizmoProperty::@331027022007232055216276241130041346111314317052 custom_func
wmGizmoGroup * parent_gzgroup
float matrix_basis[4][4]
float select_bias
float matrix_offset[4][4]
blender::Vector< wmGizmoOpElem, 4 > op_data
PointerRNA * ptr
i
Definition text_draw.cc:230
conversion and adaptation of different datablocks to a common struct.
#define GIZMO_AXIS_LINE_WIDTH
#define MAN_AXIS_RANGE_SCALE_START
#define MAN_AXIS_RANGE_ROT_END
#define MAN_TRANS_C
#define MAN_SCALE_Z
#define MAN_ROT_X
#define MAN_SCALE_X
#define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local)
#define GIZMO_NEW_DIAL(v)
#define MAN_ROT_Y
#define MAN_ROT_C
#define MAN_ITER_AXES_END
#define MAN_AXIS_RANGE_TRANS_END
#define MAN_TRANS_X
#define GIZMO_NEW_PRIM(v)
#define GIZMO_NEW_ARROW(v)
#define FOREACH_EDIT_OBJECT_END()
#define MAN_AXIS_RANGE_ROT_START
#define MAN_AXIS_SCALE_PLANE_SCALE
#define MAN_AXIS_RANGE_SCALE_END
#define MAN_ROT_Z
#define MAN_TRANS_Z
#define MAN_ITER_AXES_BEGIN(axis, axis_idx)
#define MAN_SCALE_C
#define MAN_SCALE_Y
#define MAN_TRANS_Y
#define MAN_AXIS_RANGE_TRANS_START
wmOperator * WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot)
@ TIMER
@ INBETWEEN_MOUSEMOVE
PointerRNA * ptr
Definition wm_files.cc:4238
void WM_gizmo_set_matrix_offset_location(wmGizmo *gz, const float offset[3])
Definition wm_gizmo.cc:302
wmGizmoOpElem * WM_gizmo_operator_get(wmGizmo *gz, int part_index)
Definition wm_gizmo.cc:195
void WM_gizmo_modal_set_while_modal(wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, const wmEvent *event)
Definition wm_gizmo.cc:434
void WM_gizmo_set_color_highlight(wmGizmo *gz, const float color_hi[4])
Definition wm_gizmo.cc:340
void WM_gizmo_set_line_width(wmGizmo *gz, const float line_width)
Definition wm_gizmo.cc:322
void WM_gizmo_set_fn_custom_modal(wmGizmo *gz, wmGizmoFnModal fn)
Definition wm_gizmo.cc:351
bool WM_gizmo_group_is_modal(const wmGizmoGroup *gzgroup)
Definition wm_gizmo.cc:719
bool WM_gizmo_highlight_set(wmGizmoMap *gzmap, wmGizmo *gz)
Definition wm_gizmo.cc:405
void WM_gizmo_set_scale(wmGizmo *gz, const float scale)
Definition wm_gizmo.cc:317
void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
Definition wm_gizmo.cc:287
void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
Definition wm_gizmo.cc:307
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
Definition wm_gizmo.cc:277
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
wmKeyMap * WM_gizmogroup_setup_keymap_generic_maybe_drag(const wmGizmoGroupType *, wmKeyConfig *kc)
const ListBase * WM_gizmomap_group_list(wmGizmoMap *gzmap)
wmGizmo * WM_gizmomap_get_modal(const wmGizmoMap *gzmap)
void WM_gizmo_do_msg_notify_tag_refresh(bContext *, wmMsgSubscribeKey *, wmMsgSubscribeValue *msg_val)
const wmGizmoType * WM_gizmotype_find(const StringRef idname, bool quiet)
#define WM_msg_subscribe_rna_anon_prop(mbus, type_, prop_, value)
void WM_msg_subscribe_rna(wmMsgBus *mbus, PointerRNA *ptr, const PropertyRNA *prop, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)