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