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