Blender V4.5
transform_mode.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdlib>
10
11#include "DNA_armature_types.h"
13#include "DNA_space_types.h"
15
16#include "BLI_listbase.h"
17#include "BLI_math_base.hh"
18#include "BLI_math_matrix.h"
19#include "BLI_math_rotation.h"
20#include "BLI_math_vector.h"
21#include "BLI_string.h"
22
23#include "BKE_constraint.h"
24#include "BKE_context.hh"
25
26#include "BLT_translation.hh"
27
28#include "transform.hh"
29#include "transform_convert.hh"
30#include "transform_gizmo.hh"
32#include "transform_snap.hh"
33
34/* Own include. */
35#include "transform_mode.hh"
36
37namespace blender::ed::transform {
38
40{
41 if (mode == TFM_BONESIZE) {
43 BLI_assert(ob);
44 if (ob->type != OB_ARMATURE) {
45 return TFM_RESIZE;
46 }
47 bArmature *arm = static_cast<bArmature *>(ob->data);
48 if (arm->drawtype == ARM_DRAW_TYPE_ENVELOPE) {
50 }
51 }
52
53 return mode;
54}
55
56bool transdata_check_local_center(const TransInfo *t, short around)
57{
58 return ((around == V3D_AROUND_LOCAL_ORIGINS) &&
59 ((t->options & (CTX_OBJECT | CTX_POSE_BONE)) ||
60 /* Implicit: `(t->flag & T_EDIT)`. */
62 OB_MESH,
67 OB_ARMATURE) ||
68 (t->spacetype == SPACE_GRAPH) ||
70}
71
83
85{
86 return (t->flag & T_V3D_ALIGN) && (t->options & CTX_OBJECT) &&
88 (CTX_DATA_COUNT(t->context, selected_editable_objects) == 1);
89}
90
91/* -------------------------------------------------------------------- */
94
95void protectedTransBits(short protectflag, float vec[3])
96{
97 if (protectflag & OB_LOCK_LOCX) {
98 vec[0] = 0.0f;
99 }
100 if (protectflag & OB_LOCK_LOCY) {
101 vec[1] = 0.0f;
102 }
103 if (protectflag & OB_LOCK_LOCZ) {
104 vec[2] = 0.0f;
105 }
106}
107
108/* This function only does the delta rotation. */
109static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
110{
111 /* Check that protection flags are set. */
112 if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
113 return;
114 }
115
116 if (protectflag & OB_LOCK_ROT4D) {
117 /* Quaternions getting limited as 4D entities that they are. */
118 if (protectflag & OB_LOCK_ROTW) {
119 quat[0] = oldquat[0];
120 }
121 if (protectflag & OB_LOCK_ROTX) {
122 quat[1] = oldquat[1];
123 }
124 if (protectflag & OB_LOCK_ROTY) {
125 quat[2] = oldquat[2];
126 }
127 if (protectflag & OB_LOCK_ROTZ) {
128 quat[3] = oldquat[3];
129 }
130 }
131 else {
132 /* Quaternions get limited with euler... (compatibility mode). */
133 float eul[3], oldeul[3], nquat[4], noldquat[4];
134 float qlen;
135
136 qlen = normalize_qt_qt(nquat, quat);
137 normalize_qt_qt(noldquat, oldquat);
138
139 quat_to_eul(eul, nquat);
140 quat_to_eul(oldeul, noldquat);
141
142 if (protectflag & OB_LOCK_ROTX) {
143 eul[0] = oldeul[0];
144 }
145 if (protectflag & OB_LOCK_ROTY) {
146 eul[1] = oldeul[1];
147 }
148 if (protectflag & OB_LOCK_ROTZ) {
149 eul[2] = oldeul[2];
150 }
151
152 eul_to_quat(quat, eul);
153
154 /* Restore original quat size. */
155 mul_qt_fl(quat, qlen);
156
157 /* Quaternions flip w sign to accumulate rotations correctly. */
158 if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) {
159 mul_qt_fl(quat, -1.0f);
160 }
161 }
162}
163
164static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3])
165{
166 if (protectflag & OB_LOCK_ROTX) {
167 eul[0] = oldeul[0];
168 }
169 if (protectflag & OB_LOCK_ROTY) {
170 eul[1] = oldeul[1];
171 }
172 if (protectflag & OB_LOCK_ROTZ) {
173 eul[2] = oldeul[2];
174 }
175}
176
182 short protectflag, float axis[3], float *angle, const float oldAxis[3], float oldAngle)
183{
184 /* Check that protection flags are set. */
185 if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
186 return;
187 }
188
189 if (protectflag & OB_LOCK_ROT4D) {
190 /* Axis-angle getting limited as 4D entities that they are... */
191 if (protectflag & OB_LOCK_ROTW) {
192 *angle = oldAngle;
193 }
194 if (protectflag & OB_LOCK_ROTX) {
195 axis[0] = oldAxis[0];
196 }
197 if (protectflag & OB_LOCK_ROTY) {
198 axis[1] = oldAxis[1];
199 }
200 if (protectflag & OB_LOCK_ROTZ) {
201 axis[2] = oldAxis[2];
202 }
203 }
204 else {
205 /* Axis-angle get limited with euler. */
206 float eul[3], oldeul[3];
207
209 axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle);
210
211 if (protectflag & OB_LOCK_ROTX) {
212 eul[0] = oldeul[0];
213 }
214 if (protectflag & OB_LOCK_ROTY) {
215 eul[1] = oldeul[1];
216 }
217 if (protectflag & OB_LOCK_ROTZ) {
218 eul[2] = oldeul[2];
219 }
220
222
223 /* When converting to axis-angle,
224 * we need a special exception for the case when there is no axis. */
225 if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
226 /* For now, rotate around y-axis then (so that it simply becomes the roll). */
227 axis[1] = 1.0f;
228 }
229 }
230}
231
232void protectedScaleBits(short protectflag, float scale[3])
233{
234 if (protectflag & OB_LOCK_SCALEX) {
235 scale[0] = 1.0f;
236 }
237 if (protectflag & OB_LOCK_SCALEY) {
238 scale[1] = 1.0f;
239 }
240 if (protectflag & OB_LOCK_SCALEZ) {
241 scale[2] = 1.0f;
242 }
243}
244
246
247/* -------------------------------------------------------------------- */
250
252{
253 if (td->con) {
258
259 bConstraintOb cob = {nullptr};
260 bConstraint *con;
261 float ctime = float(t->scene->r.cfra);
262
263 /* Make a temporary bConstraintOb for using these limit constraints
264 * - They only care that cob->matrix is correctly set ;-).
265 * - Current space should be local.
266 */
267 unit_m4(cob.matrix);
268 copy_v3_v3(cob.matrix[3], td->loc);
269
270 /* Evaluate valid constraints. */
271 for (con = td->con; con; con = con->next) {
272 const bConstraintTypeInfo *cti = nullptr;
273 ListBase targets = {nullptr, nullptr};
274
275 /* Only consider constraint if enabled. */
276 if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
277 continue;
278 }
279 if (con->enforce == 0.0f) {
280 continue;
281 }
282
283 /* Only use it if it's tagged for this purpose (and the right type). */
284 if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
286
287 if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
288 continue;
289 }
290 cti = ctiLoc;
291 }
292 else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
294
295 if ((data->flag & LIMITDIST_TRANSFORM) == 0) {
296 continue;
297 }
298 cti = ctiDist;
299 }
300
301 if (cti) {
302 /* Do space conversions. */
303 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
304 mul_m3_v3(td->mtx, cob.matrix[3]);
305 if (tc->use_local_mat) {
306 add_v3_v3(cob.matrix[3], tc->mat[3]);
307 }
308 }
309 else if (con->ownspace == CONSTRAINT_SPACE_POSE) {
310 /* Bone space without considering object transformations. */
311 mul_m3_v3(td->mtx, cob.matrix[3]);
312 mul_m3_v3(tc->imat3, cob.matrix[3]);
313 }
314 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
315 /* Skip... incompatible spacetype. */
316 continue;
317 }
318
319 /* Initialize the custom space for use in calculating the matrices. */
321
322 /* Get constraint targets if needed. */
323 BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
324
325 /* Do constraint. */
326 cti->evaluate_constraint(con, &cob, &targets);
327
328 /* Convert spaces again. */
329 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
330 if (tc->use_local_mat) {
331 sub_v3_v3(cob.matrix[3], tc->mat[3]);
332 }
333 mul_m3_v3(td->smtx, cob.matrix[3]);
334 }
335 else if (con->ownspace == CONSTRAINT_SPACE_POSE) {
336 mul_m3_v3(tc->mat3, cob.matrix[3]);
337 mul_m3_v3(td->smtx, cob.matrix[3]);
338 }
339
340 /* Free targets list. */
341 BLI_freelistN(&targets);
342 }
343 }
344
345 /* Copy results from `cob->matrix`. */
346 copy_v3_v3(td->loc, cob.matrix[3]);
347 }
348}
349
351{
352 /* Make a temporary bConstraintOb for use by limit constraints
353 * - they only care that cob->matrix is correctly set ;-)
354 * - current space should be local
355 */
356 memset(cob, 0, sizeof(bConstraintOb));
357 if (td->ext) {
358 if (td->ext->rotOrder == ROT_MODE_QUAT) {
359 /* Quaternion. */
360 /* Objects and bones do normalization first too, otherwise
361 * we don't necessarily end up with a rotation matrix, and
362 * then conversion back to quat gives a different result. */
363 float quat[4];
364 normalize_qt_qt(quat, td->ext->quat);
365 quat_to_mat4(cob->matrix, quat);
366 }
367 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
368 /* Axis angle. */
369 axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle);
370 }
371 else {
372 /* Eulers. */
373 eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder);
374 }
375 }
376}
377
378static void constraintRotLim(const TransInfo * /*t*/, TransData *td)
379{
380 if (td->con) {
382 bConstraintOb cob;
383 bConstraint *con;
384 bool do_limit = false;
385
386 /* Evaluate valid constraints. */
387 for (con = td->con; con; con = con->next) {
388 /* Only consider constraint if enabled. */
389 if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
390 continue;
391 }
392 if (con->enforce == 0.0f) {
393 continue;
394 }
395
396 /* We're only interested in Limit-Rotation constraints. */
397 if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
399
400 /* Only use it if it's tagged for this purpose. */
401 if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
402 continue;
403 }
404
405 /* Skip incompatible space-types. */
407 continue;
408 }
409
410 /* Only do conversion if necessary, to preserve quaternion and euler rotations. */
411 if (do_limit == false) {
413 do_limit = true;
414 }
415
416 /* Do space conversions. */
417 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
418 /* Just multiply by `td->mtx` (this should be ok). */
419 mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
420 }
421
422 /* Do constraint. */
423 cti->evaluate_constraint(con, &cob, nullptr);
424
425 /* Convert spaces again. */
426 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
427 /* Just multiply by `td->smtx` (this should be ok). */
428 mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
429 }
430 }
431 }
432
433 if (do_limit) {
434 /* Copy results from `cob->matrix`. */
435 if (td->ext->rotOrder == ROT_MODE_QUAT) {
436 /* Quaternion. */
437 mat4_to_quat(td->ext->quat, cob.matrix);
438 }
439 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
440 /* Axis angle. */
442 }
443 else {
444 /* Eulers. */
445 mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix);
446 }
447 }
448 }
449}
450
452{
453 if (td->con && td->ext) {
455 bConstraintOb cob = {nullptr};
456 bConstraint *con;
457 float scale_sign[3], scale_abs[3];
458 int i;
459
460 /* Make a temporary bConstraintOb for using these limit constraints
461 * - they only care that cob->matrix is correctly set ;-)
462 * - current space should be local
463 */
464 if ((td->flag & TD_SINGLE_SCALE) && !(t->con.mode & CON_APPLY)) {
465 /* Scale val and reset the "scale". */
466 return; /* TODO: fix this case. */
467 }
468
469 /* Reset val if SINGLESIZE but using a constraint. */
470 if (td->flag & TD_SINGLE_SCALE) {
471 return;
472 }
473
474 /* Separate out sign to apply back later. */
475 for (i = 0; i < 3; i++) {
476 scale_sign[i] = signf(td->ext->scale[i]);
477 scale_abs[i] = fabsf(td->ext->scale[i]);
478 }
479
480 size_to_mat4(cob.matrix, scale_abs);
481
482 /* Evaluate valid constraints. */
483 for (con = td->con; con; con = con->next) {
484 /* Only consider constraint if enabled. */
485 if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
486 continue;
487 }
488 if (con->enforce == 0.0f) {
489 continue;
490 }
491
492 /* We're only interested in Limit-Scale constraints. */
493 if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
494 bSizeLimitConstraint *data = static_cast<bSizeLimitConstraint *>(con->data);
495
496 /* Only use it if it's tagged for this purpose. */
497 if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
498 continue;
499 }
500
501 /* Do space conversions. */
502 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
503 /* Just multiply by `td->mtx` (this should be ok). */
504 mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
505 }
506 else if (con->ownspace == CONSTRAINT_SPACE_POSE) {
507 /* Bone space without considering object transformations. */
508 mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
509 mul_m4_m3m4(cob.matrix, tc->imat3, cob.matrix);
510 }
511 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
512 /* Skip... incompatible `spacetype`. */
513 continue;
514 }
515
516 /* Do constraint. */
517 cti->evaluate_constraint(con, &cob, nullptr);
518
519 /* Convert spaces again. */
520 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
521 /* Just multiply by `td->smtx` (this should be ok). */
522 mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
523 }
524 else if (con->ownspace == CONSTRAINT_SPACE_POSE) {
525 mul_m4_m3m4(cob.matrix, tc->mat3, cob.matrix);
526 mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
527 }
528 }
529 }
530
531 /* Copy results from `cob->matrix`. */
532 if ((td->flag & TD_SINGLE_SCALE) && !(t->con.mode & CON_APPLY)) {
533 /* Scale val and reset the "scale". */
534 return; /* TODO: fix this case. */
535 }
536
537 /* Reset val if SINGLESIZE but using a constraint. */
538 if (td->flag & TD_SINGLE_SCALE) {
539 return;
540 }
541
542 /* Extract scale from matrix and apply back sign. */
543 mat4_to_size(td->ext->scale, cob.matrix);
544 mul_v3_v3(td->ext->scale, scale_sign);
545 }
546}
547
549
550/* -------------------------------------------------------------------- */
553
554void headerRotation(TransInfo *t, char *str, const int str_size, float final)
555{
556 size_t ofs = 0;
557
558 if (hasNumInput(&t->num)) {
559 char c[NUM_STR_REP_LEN];
560
561 outputNumInput(&(t->num), c, t->scene->unit);
562
563 ofs += BLI_snprintf_rlen(
564 str + ofs, str_size - ofs, IFACE_("Rotation: %s %s %s"), &c[0], t->con.text, t->proptext);
565 }
566 else {
567 ofs += BLI_snprintf_rlen(str + ofs,
568 str_size - ofs,
569 IFACE_("Rotation: %.2f%s %s"),
570 RAD2DEGF(final),
571 t->con.text,
572 t->proptext);
573 }
574
575 if (t->flag & T_PROP_EDIT_ALL) {
576 ofs += BLI_snprintf_rlen(
577 str + ofs, str_size - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
578 }
579}
580
582 const TransDataContainer *tc,
583 TransData *td,
584 const float mat[3][3],
585 const float *center)
586{
587 float vec[3], totmat[3][3], smat[3][3];
588 float eul[3], fmat[3][3], quat[4];
589
590 if (t->flag & T_POINTS) {
591 mul_m3_m3m3(totmat, mat, td->mtx);
592 mul_m3_m3m3(smat, td->smtx, totmat);
593
594 /* Apply gpencil falloff. */
595 if (t->options & CTX_GPENCIL_STROKES) {
596 if (t->obedit_type == OB_GREASE_PENCIL) {
597 const float *gp_falloff = static_cast<const float *>(td->extra);
598 if (gp_falloff != nullptr && *gp_falloff != 1.0f) {
599 float ident_mat[3][3];
600 unit_m3(ident_mat);
601 interp_m3_m3m3(smat, ident_mat, smat, *gp_falloff);
602 }
603 }
604 }
605
606 sub_v3_v3v3(vec, td->iloc, center);
607 mul_m3_v3(smat, vec);
608
609 add_v3_v3v3(td->loc, vec, center);
610
611 sub_v3_v3v3(vec, td->loc, td->iloc);
613 add_v3_v3v3(td->loc, td->iloc, vec);
614
615 if (td->flag & TD_USEQUAT) {
616 mul_m3_series(fmat, td->smtx, mat, td->mtx);
617 mat3_to_quat(quat, fmat); /* Actual transform. */
618
619 if (td->ext->quat) {
620 mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
621
622 /* Is there a reason not to have this here? -jahka. */
624 }
625 }
626 }
639 else if (t->options & CTX_POSE_BONE) {
640 /* Extract and invert armature object matrix. */
641
642 if ((td->flag & TD_NO_LOC) == 0) {
643 sub_v3_v3v3(vec, td->center, center);
644
645 mul_m3_v3(tc->mat3, vec); /* To Global space. */
646 mul_m3_v3(mat, vec); /* Applying rotation. */
647 mul_m3_v3(tc->imat3, vec); /* To Local space. */
648
649 add_v3_v3(vec, center);
650 /* `vec` now is the location where the object has to be. */
651
652 sub_v3_v3v3(vec, vec, td->center); /* Translation needed from the initial location. */
653
654 /* Special exception, see TD_PBONE_LOCAL_MTX definition comments. */
655 if (td->flag & TD_PBONE_LOCAL_MTX_P) {
656 /* Do nothing. */
657 }
658 else if (td->flag & TD_PBONE_LOCAL_MTX_C) {
659 mul_m3_v3(tc->mat3, vec); /* To Global space. */
660 mul_m3_v3(td->ext->l_smtx, vec); /* To Pose space (Local Location). */
661 }
662 else {
663 mul_m3_v3(tc->mat3, vec); /* To Global space. */
664 mul_m3_v3(td->smtx, vec); /* To Pose space. */
665 }
666
668
669 add_v3_v3v3(td->loc, td->iloc, vec);
670
671 constraintTransLim(t, tc, td);
672 }
673
674 /* Rotation. */
675 /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same,
676 * and ElementRotation() might be called in Translation context (with align snapping),
677 * we need to be sure to actually use the *rotation* matrix here...
678 * So no other way than storing it in some dedicated members of `td->ext`! */
679 if ((t->flag & T_V3D_ALIGN) == 0) { /* Align mode doesn't rotate objects itself. */
680 /* Euler or quaternion/axis-angle? */
681 if (td->ext->rotOrder == ROT_MODE_QUAT) {
682 mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
683
684 mat3_to_quat(quat, fmat); /* Actual transform. */
685
686 mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
687 /* This function works on end result. */
689 }
690 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
691 /* Calculate effect based on quaternions. */
692 float iquat[4], tquat[4];
693
694 axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
695
696 mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
697 mat3_to_quat(quat, fmat); /* Actual transform. */
698 mul_qt_qtqt(tquat, quat, iquat);
699
700 quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
701
702 /* This function works on end result. */
704 td->ext->rotAxis,
705 td->ext->rotAngle,
706 td->ext->irotAxis,
707 td->ext->irotAngle);
708 }
709 else {
710 float eulmat[3][3];
711
712 mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
713 mul_m3_m3m3(smat, td->ext->r_smtx, totmat);
714
715 /* Calculate the total rotation in eulers. */
716 copy_v3_v3(eul, td->ext->irot);
717 eulO_to_mat3(eulmat, eul, td->ext->rotOrder);
718
719 /* `mat = transform`, `obmat = bone rotation`. */
720 mul_m3_m3m3(fmat, smat, eulmat);
721
722 mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
723
724 /* And apply (to end result only). */
725 protectedRotateBits(td->protectflag, eul, td->ext->irot);
726 copy_v3_v3(td->ext->rot, eul);
727 }
728
729 constraintRotLim(t, td);
730 }
731 }
732 else {
733 if ((td->flag & TD_NO_LOC) == 0) {
734 /* Translation. */
735 sub_v3_v3v3(vec, td->center, center);
736 mul_m3_v3(mat, vec);
737 add_v3_v3(vec, center);
738 /* `vec` now is the location where the object has to be. */
739 sub_v3_v3(vec, td->center);
740 mul_m3_v3(td->smtx, vec);
741
743
744 add_v3_v3v3(td->loc, td->iloc, vec);
745 }
746
747 constraintTransLim(t, tc, td);
748
749 /* Rotation. */
750 if ((t->flag & T_V3D_ALIGN) == 0) { /* Align mode doesn't rotate objects itself. */
751 /* Euler or quaternion? */
752 if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
753 /* Can be called for texture space translate for example, then opt out. */
754 if (td->ext->quat) {
755 mul_m3_series(fmat, td->smtx, mat, td->mtx);
756
757 if (!is_zero_v3(td->ext->dquat)) {
758 /* Correct for delta quat. */
759 float tmp_mat[3][3];
760 quat_to_mat3(tmp_mat, td->ext->dquat);
761 mul_m3_m3m3(fmat, fmat, tmp_mat);
762 }
763
764 mat3_to_quat(quat, fmat); /* Actual transform. */
765
766 if (!is_zero_v4(td->ext->dquat)) {
767 /* Correct back for delta quaternion. */
768 float idquat[4];
769 invert_qt_qt_normalized(idquat, td->ext->dquat);
770 mul_qt_qtqt(quat, idquat, quat);
771 }
772
773 mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
774
775 /* This function works on end result. */
777 }
778 }
779 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
780 /* Calculate effect based on quaternions. */
781 float iquat[4], tquat[4];
782
783 axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
784
785 mul_m3_series(fmat, td->smtx, mat, td->mtx);
786 mat3_to_quat(quat, fmat); /* Actual transform. */
787 mul_qt_qtqt(tquat, quat, iquat);
788
789 quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
790
791 /* This function works on end result. */
793 td->ext->rotAxis,
794 td->ext->rotAngle,
795 td->ext->irotAxis,
796 td->ext->irotAngle);
797 }
798 else {
799 /* Calculate the total rotation in eulers. */
800 float obmat[3][3];
801
802 mul_m3_m3m3(totmat, mat, td->mtx);
803 mul_m3_m3m3(smat, td->smtx, totmat);
804
805 if (!is_zero_v3(td->ext->drot)) {
806 /* Correct for delta rot. */
807 add_eul_euleul(eul, td->ext->irot, td->ext->drot, td->ext->rotOrder);
808 }
809 else {
810 copy_v3_v3(eul, td->ext->irot);
811 }
812
813 eulO_to_mat3(obmat, eul, td->ext->rotOrder);
814 mul_m3_m3m3(fmat, smat, obmat);
815 mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
816
817 if (!is_zero_v3(td->ext->drot)) {
818 /* Correct back for delta rot. */
819 sub_eul_euleul(eul, eul, td->ext->drot, td->ext->rotOrder);
820 }
821
822 /* And apply. */
823 protectedRotateBits(td->protectflag, eul, td->ext->irot);
824 copy_v3_v3(td->ext->rot, eul);
825 }
826
827 constraintRotLim(t, td);
828 }
829 }
830}
831
833 const TransDataContainer *tc,
834 TransData *td,
835 const float mat[3][3],
836 const short around)
837{
838 const float *center;
839
840 /* Local constraint shouldn't alter center. */
841 if (transdata_check_local_center(t, around)) {
842 center = td->center;
843 }
844 else {
845 center = tc->center_local;
846 }
847
848 ElementRotation_ex(t, tc, td, mat, center);
849}
850
852
853/* -------------------------------------------------------------------- */
856
857void headerResize(TransInfo *t, const float vec[3], char *str, const int str_size)
858{
859 char tvec[NUM_STR_REP_LEN * 3];
860 size_t ofs = 0;
861 if (hasNumInput(&t->num)) {
862 outputNumInput(&(t->num), tvec, t->scene->unit);
863 }
864 else {
865 BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
866 BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
867 BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
868 }
869
870 if (t->con.mode & CON_APPLY) {
871 switch (t->num.idx_max) {
872 case 0:
873 ofs += BLI_snprintf_rlen(str + ofs,
874 str_size - ofs,
875 IFACE_("Scale: %s%s %s"),
876 &tvec[0],
877 t->con.text,
878 t->proptext);
879 break;
880 case 1:
881 ofs += BLI_snprintf_rlen(str + ofs,
882 str_size - ofs,
883 IFACE_("Scale: %s : %s%s %s"),
884 &tvec[0],
885 &tvec[NUM_STR_REP_LEN],
886 t->con.text,
887 t->proptext);
888 break;
889 case 2:
890 ofs += BLI_snprintf_rlen(str + ofs,
891 str_size - ofs,
892 IFACE_("Scale: %s : %s : %s%s %s"),
893 &tvec[0],
894 &tvec[NUM_STR_REP_LEN],
895 &tvec[NUM_STR_REP_LEN * 2],
896 t->con.text,
897 t->proptext);
898 break;
899 }
900 }
901 else {
902 if (t->flag & T_2D_EDIT) {
903 ofs += BLI_snprintf_rlen(str + ofs,
904 str_size - ofs,
905 IFACE_("Scale X: %s Y: %s%s %s"),
906 &tvec[0],
907 &tvec[NUM_STR_REP_LEN],
908 t->con.text,
909 t->proptext);
910 }
911 else {
912 ofs += BLI_snprintf_rlen(str + ofs,
913 str_size - ofs,
914 IFACE_("Scale X: %s Y: %s Z: %s%s %s"),
915 &tvec[0],
916 &tvec[NUM_STR_REP_LEN],
917 &tvec[NUM_STR_REP_LEN * 2],
918 t->con.text,
919 t->proptext);
920 }
921 }
922
923 if (t->flag & T_PROP_EDIT_ALL) {
924 ofs += BLI_snprintf_rlen(
925 str + ofs, str_size - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
926 }
927}
928
934static void TransMat3ToSize(const float mat[3][3], const float smat[3][3], float size[3])
935{
936 float rmat[3][3];
937
938 mat3_to_rot_size(rmat, size, mat);
939
940 /* First tried with dot-product... but the sign flip is crucial. */
941 if (dot_v3v3(rmat[0], smat[0]) < 0.0f) {
942 size[0] = -size[0];
943 }
944 if (dot_v3v3(rmat[1], smat[1]) < 0.0f) {
945 size[1] = -size[1];
946 }
947 if (dot_v3v3(rmat[2], smat[2]) < 0.0f) {
948 size[2] = -size[2];
949 }
950}
951
953 const TransDataContainer *tc,
954 TransData *td,
955 const float mat[3][3])
956{
957 float tmat[3][3], smat[3][3], center[3];
958 float vec[3];
959
960 if (t->flag & T_EDIT) {
961 mul_m3_m3m3(smat, mat, td->mtx);
962 mul_m3_m3m3(tmat, td->smtx, smat);
963 }
964 else {
965 copy_m3_m3(tmat, mat);
966 }
967
968 if (t->con.applySize) {
969 t->con.applySize(t, tc, td, tmat);
970 }
971
972 /* Local constraint shouldn't alter center. */
974 copy_v3_v3(center, td->center);
975 }
976 else if (t->options & CTX_MOVIECLIP) {
977 if (td->flag & TD_INDIVIDUAL_SCALE) {
978 copy_v3_v3(center, td->center);
979 }
980 else {
981 copy_v3_v3(center, tc->center_local);
982 }
983 }
984 else {
985 copy_v3_v3(center, tc->center_local);
986 }
987
988 /* Size checked needed since the 3D cursor only uses rotation fields. */
989 if (td->ext && td->ext->scale) {
990 float fscale[3];
991
992 if (ELEM(t->data_type,
997 {
998 float ob_scale_mat[3][3];
999 /* Reorient the size mat to fit the oriented object. */
1000 mul_m3_m3m3(ob_scale_mat, tmat, td->axismtx);
1001 // print_m3("ob_scale_mat", ob_scale_mat);
1002 TransMat3ToSize(ob_scale_mat, td->axismtx, fscale);
1003 // print_v3("fscale", fscale);
1004 }
1005 else {
1006 mat3_to_size(fscale, tmat);
1007 }
1008
1009 protectedScaleBits(td->protectflag, fscale);
1010
1011 if ((t->flag & T_V3D_ALIGN) == 0) { /* Align mode doesn't resize objects itself. */
1012 if ((td->flag & TD_SINGLE_SCALE) && !(t->con.mode & CON_APPLY)) {
1013 /* Scale val and reset scale. */
1014 *td->val = td->ival * (1 + (fscale[0] - 1) * td->factor);
1015
1016 td->ext->scale[0] = td->ext->iscale[0];
1017 td->ext->scale[1] = td->ext->iscale[1];
1018 td->ext->scale[2] = td->ext->iscale[2];
1019 }
1020 else {
1021 /* Reset val if #TD_SINGLE_SCALE but using a constraint. */
1022 if (td->flag & TD_SINGLE_SCALE) {
1023 *td->val = td->ival;
1024 }
1025
1026 td->ext->scale[0] = td->ext->iscale[0] * (1 + (fscale[0] - 1) * td->factor);
1027 td->ext->scale[1] = td->ext->iscale[1] * (1 + (fscale[1] - 1) * td->factor);
1028 td->ext->scale[2] = td->ext->iscale[2] * (1 + (fscale[2] - 1) * td->factor);
1029 }
1030 }
1031
1032 constraintScaleLim(t, tc, td);
1033 }
1034
1035 /* For individual element center, Editmode need to use iloc. */
1036 if (t->flag & T_POINTS) {
1037 sub_v3_v3v3(vec, td->iloc, center);
1038 }
1039 else {
1040 sub_v3_v3v3(vec, td->center, center);
1041 }
1042
1043 mul_m3_v3(tmat, vec);
1044
1045 add_v3_v3(vec, center);
1046 if (t->flag & T_POINTS) {
1047 sub_v3_v3(vec, td->iloc);
1048 }
1049 else {
1050 sub_v3_v3(vec, td->center);
1051 }
1052
1053 /* Grease pencil falloff.
1054 *
1055 * FIXME: This is bad on multiple levels!
1056 *
1057 * - #applyNumInput is not intended to be run for every element,
1058 * this writes back into the number input in a way that doesn't make sense to run many times.
1059 *
1060 * - Writing into #TransInfo should be avoided since it means order of operations
1061 * may impact the result and isn't thread-safe.
1062 *
1063 * Operating on copies as a temporary solution.
1064 */
1065 if (t->options & CTX_GPENCIL_STROKES) {
1066 const float *gp_falloff_ptr = static_cast<const float *>(td->extra);
1067 const float gp_falloff = gp_falloff_ptr != nullptr ? *gp_falloff_ptr : 1.0f;
1068 mul_v3_fl(vec, td->factor * gp_falloff);
1069
1070 /* Scale stroke thickness. */
1071 if (td->val) {
1072 NumInput num_evil = t->num;
1073 float values_final_evil[4];
1074 copy_v4_v4(values_final_evil, t->values_final);
1075 transform_snap_increment(t, values_final_evil);
1076 applyNumInput(&num_evil, values_final_evil);
1077
1078 float ratio = values_final_evil[0];
1079 float transformed_value = td->ival * fabs(ratio);
1080 *td->val = math::max(math::interpolate(td->ival, transformed_value, gp_falloff), 0.001f);
1081 }
1082 }
1083 else {
1084 mul_v3_fl(vec, td->factor);
1085 }
1086
1087 if (t->options & (CTX_OBJECT | CTX_POSE_BONE)) {
1088 if (t->options & CTX_POSE_BONE) {
1089 /* Without this, the resulting location of scaled bones aren't correct,
1090 * especially noticeable scaling root or disconnected bones around the cursor, see #92515. */
1091 mul_mat3_m4_v3(tc->poseobj->object_to_world().ptr(), vec);
1092 }
1093 mul_m3_v3(td->smtx, vec);
1094 }
1095
1097 if (td->loc) {
1098 add_v3_v3v3(td->loc, td->iloc, vec);
1099 }
1100
1101 constraintTransLim(t, tc, td);
1102}
1103
1105
1106/* -------------------------------------------------------------------- */
1109
1110static TransModeInfo *mode_info_get(TransInfo *t, const int mode)
1111{
1112 switch (mode) {
1113 case TFM_TRANSLATION:
1114 return &TransMode_translate;
1115 case TFM_ROTATION:
1116 return &TransMode_rotate;
1117 case TFM_RESIZE:
1118 return &TransMode_resize;
1119 case TFM_SKIN_RESIZE:
1120 return &TransMode_skinresize;
1121 case TFM_TOSPHERE:
1122 return &TransMode_tosphere;
1123 case TFM_SHEAR:
1124 return &TransMode_shear;
1125 case TFM_BEND:
1126 return &TransMode_bend;
1127 case TFM_SHRINKFATTEN:
1128 return &TransMode_shrinkfatten;
1129 case TFM_TILT:
1130 return &TransMode_tilt;
1135 case TFM_TRACKBALL:
1136 return &TransMode_trackball;
1137 case TFM_PUSHPULL:
1138 return &TransMode_pushpull;
1139 case TFM_EDGE_CREASE:
1140 return &TransMode_edgecrease;
1141 case TFM_VERT_CREASE:
1142 return &TransMode_vertcrease;
1143 case TFM_BONESIZE:
1144 return &TransMode_bboneresize;
1145 case TFM_BONE_ENVELOPE:
1147 return &TransMode_boneenvelope;
1148 case TFM_EDGE_SLIDE:
1149 return &TransMode_edgeslide;
1150 case TFM_VERT_SLIDE:
1151 return &TransMode_vertslide;
1152 case TFM_BONE_ROLL:
1153 return &TransMode_boneroll;
1154 case TFM_TIME_TRANSLATE:
1156 case TFM_TIME_SLIDE:
1157 return &TransMode_timeslide;
1158 case TFM_TIME_SCALE:
1159 return &TransMode_timescale;
1160 case TFM_TIME_EXTEND:
1161 /* Do TFM_TIME_TRANSLATE (for most Animation Editors because they have only 1D transforms for
1162 * time values) or TFM_TRANSLATION (for Graph/NLA Editors only since they uses 'standard'
1163 * transforms to get 2D movement) depending on which editor this was called from. */
1164 if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
1165 return &TransMode_translate;
1166 }
1168 case TFM_BAKE_TIME:
1169 return &TransMode_baketime;
1170 case TFM_MIRROR:
1171 return &TransMode_mirror;
1172 case TFM_BWEIGHT:
1173 return &TransMode_bevelweight;
1174 case TFM_ALIGN:
1175 return &TransMode_align;
1176 case TFM_SEQ_SLIDE:
1177 return &TransMode_seqslide;
1179 return &TransMode_rotatenormal;
1181 return &TransMode_gpopacity;
1182 }
1183 return nullptr;
1184}
1185
1186void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
1187{
1188 t->mode = eTfmMode(mode);
1189 t->mode_info = mode_info_get(t, mode);
1190
1191 if (t->mode_info) {
1192 t->flag |= eTFlag(t->mode_info->flags);
1193 t->mode_info->init_fn(t, op);
1194 }
1195
1196 if (t->data_type == &TransConvertType_Mesh) {
1197 /* Init Custom Data correction.
1198 * Ideally this should be called when creating the TransData. */
1200 }
1201
1203
1204 /* TODO(@mano-wii): Some of these operations change the `t->mode`.
1205 * This can be bad for Redo. */
1206 // BLI_assert(t->mode == mode);
1207}
1208
1210{
1211 /* Currently only these types are supported. */
1213
1215 return;
1216 }
1217
1218 if (!(t->flag & T_MODAL)) {
1219 return;
1220 }
1221
1222 if (t->orient[O_DEFAULT].type == type) {
1223 return;
1224 }
1225
1226 View3D *v3d = nullptr;
1227 RegionView3D *rv3d = nullptr;
1228 if ((type == V3D_ORIENT_VIEW) && (t->spacetype == SPACE_VIEW3D) && t->region &&
1230 {
1231 v3d = static_cast<View3D *>(t->view);
1232 rv3d = static_cast<RegionView3D *>(t->region->regiondata);
1233 }
1234
1236 t->view_layer,
1237 v3d,
1238 rv3d,
1239 nullptr,
1240 nullptr,
1241 type,
1243 t->orient[O_DEFAULT].matrix);
1244
1245 if (t->orient_curr == O_DEFAULT) {
1246 /* Update Orientation. */
1248 }
1249}
1250
1252
1253} // namespace blender::ed::transform
void BKE_constraint_custom_object_space_init(struct bConstraintOb *cob, struct bConstraint *con)
void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime)
const bConstraintTypeInfo * BKE_constraint_typeinfo_from_type(int type)
Object * CTX_data_active_object(const bContext *C)
#define CTX_DATA_COUNT(C, member)
#define BLI_assert(a)
Definition BLI_assert.h:46
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
MINLINE float signf(float f)
#define RAD2DEGF(_rad)
void mul_m3_v3(const float M[3][3], float r[3])
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void unit_m3(float m[3][3])
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3])
void size_to_mat4(float R[4][4], const float size[3])
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], float t)
void mat4_to_size(float size[3], const float M[4][4])
#define mul_m3_series(...)
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void mat3_to_size(float size[3], const float M[3][3])
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
void unit_m4(float m[4][4])
void sub_eul_euleul(float r_eul[3], float a[3], float b[3], short order)
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void quat_to_mat3(float m[3][3], const float q[4])
@ EULER_ORDER_DEFAULT
void mat3_to_quat(float q[4], const float mat[3][3])
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], short order)
void quat_to_mat4(float m[4][4], const float q[4])
void mul_qt_fl(float q[4], float f)
void eul_to_quat(float quat[4], const float eul[3])
void axis_angle_to_mat4(float R[4][4], const float axis[3], float angle)
void eulO_to_mat4(float mat[4][4], const float e[3], short order)
void mat4_to_axis_angle(float axis[3], float *angle, const float mat[4][4])
void quat_to_eul(float eul[3], const float quat[4])
float normalize_qt_qt(float r[4], const float q[4])
void invert_qt_qt_normalized(float q1[4], const float q2[4])
void mat4_to_eulO(float eul[3], short order, const float m[4][4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
void axis_angle_to_eulO(float eul[3], short order, const float axis[3], float angle)
void mat4_to_quat(float q[4], const float mat[4][4])
void mat3_to_compatible_eulO(float eul[3], const float oldrot[3], short order, const float mat[3][3])
void eulO_to_mat3(float M[3][3], const float e[3], short order)
void add_eul_euleul(float r_eul[3], float a[3], float b[3], short order)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v4(const float v[4]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
size_t BLI_snprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define ELEM(...)
#define IS_EQF(a, b)
#define IFACE_(msgid)
@ ROT_MODE_QUAT
@ ROT_MODE_AXISANGLE
@ ARM_DRAW_TYPE_ENVELOPE
@ CONSTRAINT_OFF
@ CONSTRAINT_DISABLE
@ CONSTRAINT_TYPE_ROTLIMIT
@ CONSTRAINT_TYPE_DISTLIMIT
@ CONSTRAINT_TYPE_LOCLIMIT
@ CONSTRAINT_TYPE_SIZELIMIT
@ CONSTRAINT_SPACE_POSE
@ CONSTRAINT_SPACE_WORLD
@ CONSTRAINT_SPACE_LOCAL
@ LIMIT_TRANSFORM
@ LIMITDIST_TRANSFORM
@ OB_LOCK_ROTZ
@ OB_LOCK_ROT4D
@ OB_LOCK_SCALEZ
@ OB_LOCK_ROTX
@ OB_LOCK_SCALEX
@ OB_LOCK_ROTW
@ OB_LOCK_LOCY
@ OB_LOCK_LOCZ
@ OB_LOCK_ROTY
@ OB_LOCK_SCALEY
@ OB_LOCK_LOCX
@ OB_MBALL
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVES_LEGACY
@ OB_CURVES
@ RGN_TYPE_WINDOW
@ SPACE_NLA
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CURSOR
@ V3D_AROUND_LOCAL_ORIGINS
@ V3D_ORIENT_GLOBAL
@ V3D_ORIENT_VIEW
#define NUM_STR_REP_LEN
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:189
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:87
bool hasNumInput(const NumInput *n)
Definition numinput.cc:170
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
#define C
Definition RandGen.cpp:29
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define fabsf(x)
#define str(s)
ccl_device_inline float2 fabs(const float2 a)
TransConvertTypeInfo TransConvertType_Pose
TransConvertTypeInfo TransConvertType_Mesh
static void protectedAxisAngleBits(short protectflag, float axis[3], float *angle, const float oldAxis[3], float oldAngle)
TransConvertTypeInfo TransConvertType_Sculpt
bool transform_mode_is_changeable(const int mode)
void headerRotation(TransInfo *t, char *str, const int str_size, float final)
static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3])
bool transform_snap_increment(const TransInfo *t, float *r_val)
void ElementRotation(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3], const short around)
void protectedTransBits(short protectflag, float vec[3])
void protectedScaleBits(short protectflag, float scale[3])
void transform_convert_mesh_customdatacorrect_init(TransInfo *t)
void headerResize(TransInfo *t, const float vec[3], char *str, const int str_size)
static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
eTfmMode transform_mode_really_used(bContext *C, eTfmMode mode)
void transform_gizmo_3d_model_from_constraint_and_mode_set(TransInfo *t)
bool transform_mode_affect_only_locations(const TransInfo *t)
static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
void constraintScaleLim(const TransInfo *t, const TransDataContainer *tc, TransData *td)
static TransModeInfo * mode_info_get(TransInfo *t, const int mode)
void ElementRotation_ex(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3], const float *center)
static void constraintRotLim(const TransInfo *, TransData *td)
void ElementResize(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3])
void constraintTransLim(const TransInfo *t, const TransDataContainer *tc, TransData *td)
TransConvertTypeInfo TransConvertType_Object
bool transdata_check_local_center(const TransInfo *t, short around)
void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
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])
static void TransMat3ToSize(const float mat[3][3], const float smat[3][3], float size[3])
void transform_orientations_current_set(TransInfo *t, const short orient_index)
T interpolate(const T &a, const T &b, const FactorT &t)
T max(const T &a, const T &b)
void * regiondata
short idx_max
struct RenderData r
struct UnitSettings unit
float matrix[4][4]
void(* evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets)
struct bConstraint * next
void(* applySize)(const TransInfo *t, const TransDataContainer *tc, const TransData *td, float r_smat[3][3])
Definition transform.hh:585
TransConvertTypeInfo * data_type
Definition transform.hh:805
struct blender::ed::transform::TransInfo::@233150133324350356161127343065016153253207070177 orient[3]
void(* init_fn)(TransInfo *, wmOperator *)
i
Definition text_draw.cc:230
#define T_PROP_EDIT_ALL
Definition transform.hh:28
conversion and adaptation of different datablocks to a common struct.
transform modes used by different operators.