2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
|
2020-02-14 08:42:17 -03:00
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup edtransform
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#include "DNA_anim_types.h"
|
2020-02-21 10:42:56 -03:00
|
|
|
#include "DNA_armature_types.h"
|
2020-02-14 08:42:17 -03:00
|
|
|
#include "DNA_constraint_types.h"
|
|
|
|
|
#include "DNA_gpencil_types.h"
|
2020-02-21 10:42:56 -03:00
|
|
|
#include "DNA_windowmanager_types.h"
|
2020-02-14 08:42:17 -03:00
|
|
|
|
|
|
|
|
#include "BLI_listbase.h"
|
|
|
|
|
#include "BLI_math.h"
|
|
|
|
|
#include "BLI_string.h"
|
|
|
|
|
|
|
|
|
|
#include "BKE_constraint.h"
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
|
#include "BKE_nla.h"
|
|
|
|
|
|
2020-02-21 10:42:56 -03:00
|
|
|
#include "RNA_access.h"
|
|
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
#include "UI_interface.h"
|
|
|
|
|
|
|
|
|
|
#include "BLT_translation.h"
|
|
|
|
|
|
|
|
|
|
#include "transform.h"
|
2020-06-10 16:36:07 -03:00
|
|
|
#include "transform_convert.h"
|
2021-05-11 23:40:06 -03:00
|
|
|
#include "transform_orientations.h"
|
2020-02-14 08:42:17 -03:00
|
|
|
#include "transform_snap.h"
|
|
|
|
|
|
|
|
|
|
/* Own include. */
|
|
|
|
|
#include "transform_mode.h"
|
|
|
|
|
|
2020-06-22 19:06:04 -03:00
|
|
|
int transform_mode_really_used(bContext *C, int mode)
|
|
|
|
|
{
|
|
|
|
|
if (mode == TFM_BONESIZE) {
|
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
|
BLI_assert(ob);
|
|
|
|
|
if (ob->type != OB_ARMATURE) {
|
|
|
|
|
return TFM_RESIZE;
|
|
|
|
|
}
|
|
|
|
|
bArmature *arm = ob->data;
|
|
|
|
|
if (arm->drawtype == ARM_ENVELOPE) {
|
|
|
|
|
return TFM_BONE_ENVELOPE_DIST;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mode;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
bool transdata_check_local_center(const TransInfo *t, short around)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
return ((around == V3D_AROUND_LOCAL_ORIGINS) &&
|
2021-02-05 11:56:43 -03:00
|
|
|
((t->options & (CTX_OBJECT | CTX_POSE_BONE)) ||
|
2020-02-14 08:42:17 -03:00
|
|
|
/* implicit: (t->flag & T_EDIT) */
|
2022-02-18 09:50:29 -06:00
|
|
|
(ELEM(t->obedit_type, OB_MESH, OB_CURVES_LEGACY, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) ||
|
2020-02-14 08:42:17 -03:00
|
|
|
(t->spacetype == SPACE_GRAPH) ||
|
2021-09-21 09:38:30 +02:00
|
|
|
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE | CTX_SEQUENCER_IMAGE))));
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
|
2020-05-21 10:57:35 -03:00
|
|
|
bool transform_mode_is_changeable(const int mode)
|
|
|
|
|
{
|
|
|
|
|
return ELEM(mode,
|
|
|
|
|
TFM_ROTATION,
|
|
|
|
|
TFM_RESIZE,
|
|
|
|
|
TFM_TRACKBALL,
|
|
|
|
|
TFM_TRANSLATION,
|
|
|
|
|
TFM_EDGE_SLIDE,
|
|
|
|
|
TFM_VERT_SLIDE);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 16:36:01 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Transform Locks
|
|
|
|
|
* \{ */
|
2020-02-14 08:42:17 -03:00
|
|
|
|
|
|
|
|
void protectedTransBits(short protectflag, float vec[3])
|
|
|
|
|
{
|
|
|
|
|
if (protectflag & OB_LOCK_LOCX) {
|
|
|
|
|
vec[0] = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_LOCY) {
|
|
|
|
|
vec[1] = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_LOCZ) {
|
|
|
|
|
vec[2] = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this function only does the delta rotation */
|
|
|
|
|
static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
|
|
|
|
|
{
|
|
|
|
|
/* check that protection flags are set */
|
|
|
|
|
if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (protectflag & OB_LOCK_ROT4D) {
|
|
|
|
|
/* quaternions getting limited as 4D entities that they are... */
|
|
|
|
|
if (protectflag & OB_LOCK_ROTW) {
|
|
|
|
|
quat[0] = oldquat[0];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTX) {
|
|
|
|
|
quat[1] = oldquat[1];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTY) {
|
|
|
|
|
quat[2] = oldquat[2];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTZ) {
|
|
|
|
|
quat[3] = oldquat[3];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* quaternions get limited with euler... (compatibility mode) */
|
|
|
|
|
float eul[3], oldeul[3], nquat[4], noldquat[4];
|
|
|
|
|
float qlen;
|
|
|
|
|
|
|
|
|
|
qlen = normalize_qt_qt(nquat, quat);
|
|
|
|
|
normalize_qt_qt(noldquat, oldquat);
|
|
|
|
|
|
|
|
|
|
quat_to_eul(eul, nquat);
|
|
|
|
|
quat_to_eul(oldeul, noldquat);
|
|
|
|
|
|
|
|
|
|
if (protectflag & OB_LOCK_ROTX) {
|
|
|
|
|
eul[0] = oldeul[0];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTY) {
|
|
|
|
|
eul[1] = oldeul[1];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTZ) {
|
|
|
|
|
eul[2] = oldeul[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eul_to_quat(quat, eul);
|
|
|
|
|
|
|
|
|
|
/* restore original quat size */
|
|
|
|
|
mul_qt_fl(quat, qlen);
|
|
|
|
|
|
|
|
|
|
/* quaternions flip w sign to accumulate rotations correctly */
|
|
|
|
|
if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) {
|
|
|
|
|
mul_qt_fl(quat, -1.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3])
|
|
|
|
|
{
|
|
|
|
|
if (protectflag & OB_LOCK_ROTX) {
|
|
|
|
|
eul[0] = oldeul[0];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTY) {
|
|
|
|
|
eul[1] = oldeul[1];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTZ) {
|
|
|
|
|
eul[2] = oldeul[2];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this function only does the delta rotation */
|
|
|
|
|
/* axis-angle is usually internally stored as quats... */
|
|
|
|
|
static void protectedAxisAngleBits(
|
2020-08-07 22:56:13 +10:00
|
|
|
short protectflag, float axis[3], float *angle, const float oldAxis[3], float oldAngle)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
/* check that protection flags are set */
|
|
|
|
|
if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (protectflag & OB_LOCK_ROT4D) {
|
|
|
|
|
/* axis-angle getting limited as 4D entities that they are... */
|
|
|
|
|
if (protectflag & OB_LOCK_ROTW) {
|
|
|
|
|
*angle = oldAngle;
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTX) {
|
|
|
|
|
axis[0] = oldAxis[0];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTY) {
|
|
|
|
|
axis[1] = oldAxis[1];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTZ) {
|
|
|
|
|
axis[2] = oldAxis[2];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* axis-angle get limited with euler... */
|
|
|
|
|
float eul[3], oldeul[3];
|
|
|
|
|
|
|
|
|
|
axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle);
|
|
|
|
|
axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle);
|
|
|
|
|
|
|
|
|
|
if (protectflag & OB_LOCK_ROTX) {
|
|
|
|
|
eul[0] = oldeul[0];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTY) {
|
|
|
|
|
eul[1] = oldeul[1];
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_ROTZ) {
|
|
|
|
|
eul[2] = oldeul[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT);
|
|
|
|
|
|
|
|
|
|
/* When converting to axis-angle,
|
|
|
|
|
* we need a special exception for the case when there is no axis. */
|
|
|
|
|
if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
|
|
|
|
|
/* for now, rotate around y-axis then (so that it simply becomes the roll) */
|
|
|
|
|
axis[1] = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 09:09:26 -03:00
|
|
|
void protectedSizeBits(short protectflag, float size[3])
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
if (protectflag & OB_LOCK_SCALEX) {
|
|
|
|
|
size[0] = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_SCALEY) {
|
|
|
|
|
size[1] = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
if (protectflag & OB_LOCK_SCALEZ) {
|
|
|
|
|
size[2] = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 16:36:01 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Transform Limits
|
|
|
|
|
* \{ */
|
2020-02-14 08:42:17 -03:00
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
void constraintTransLim(const TransInfo *t, TransData *td)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
if (td->con) {
|
|
|
|
|
const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(
|
|
|
|
|
CONSTRAINT_TYPE_LOCLIMIT);
|
|
|
|
|
const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(
|
|
|
|
|
CONSTRAINT_TYPE_DISTLIMIT);
|
|
|
|
|
|
|
|
|
|
bConstraintOb cob = {NULL};
|
|
|
|
|
bConstraint *con;
|
|
|
|
|
float ctime = (float)(t->scene->r.cfra);
|
|
|
|
|
|
|
|
|
|
/* Make a temporary bConstraintOb for using these limit constraints
|
|
|
|
|
* - they only care that cob->matrix is correctly set ;-)
|
|
|
|
|
* - current space should be local
|
|
|
|
|
*/
|
|
|
|
|
unit_m4(cob.matrix);
|
|
|
|
|
copy_v3_v3(cob.matrix[3], td->loc);
|
|
|
|
|
|
|
|
|
|
/* Evaluate valid constraints */
|
|
|
|
|
for (con = td->con; con; con = con->next) {
|
|
|
|
|
const bConstraintTypeInfo *cti = NULL;
|
|
|
|
|
ListBase targets = {NULL, NULL};
|
|
|
|
|
|
|
|
|
|
/* only consider constraint if enabled */
|
|
|
|
|
if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (con->enforce == 0.0f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* only use it if it's tagged for this purpose (and the right type) */
|
|
|
|
|
if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
|
|
|
|
|
bLocLimitConstraint *data = (bLocLimitConstraint *)con->data;
|
|
|
|
|
|
|
|
|
|
if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
cti = ctiLoc;
|
|
|
|
|
}
|
|
|
|
|
else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
|
|
|
|
|
bDistLimitConstraint *data = (bDistLimitConstraint *)con->data;
|
|
|
|
|
|
|
|
|
|
if ((data->flag & LIMITDIST_TRANSFORM) == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
cti = ctiDist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cti) {
|
|
|
|
|
/* do space conversions */
|
|
|
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
|
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
|
|
|
mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
|
|
|
|
|
/* skip... incompatible spacetype */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get constraint targets if needed */
|
|
|
|
|
BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
|
|
|
|
|
|
|
|
|
|
/* do constraint */
|
|
|
|
|
cti->evaluate_constraint(con, &cob, &targets);
|
|
|
|
|
|
|
|
|
|
/* convert spaces again */
|
|
|
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
|
|
|
/* just multiply by td->smtx (this should be ok) */
|
|
|
|
|
mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* free targets list */
|
|
|
|
|
BLI_freelistN(&targets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* copy results from cob->matrix */
|
|
|
|
|
copy_v3_v3(td->loc, cob.matrix[3]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
|
|
|
|
|
{
|
|
|
|
|
/* Make a temporary bConstraintOb for use by limit constraints
|
|
|
|
|
* - they only care that cob->matrix is correctly set ;-)
|
|
|
|
|
* - current space should be local
|
|
|
|
|
*/
|
|
|
|
|
memset(cob, 0, sizeof(bConstraintOb));
|
|
|
|
|
if (td->ext) {
|
|
|
|
|
if (td->ext->rotOrder == ROT_MODE_QUAT) {
|
|
|
|
|
/* quats */
|
|
|
|
|
/* objects and bones do normalization first too, otherwise
|
|
|
|
|
* we don't necessarily end up with a rotation matrix, and
|
|
|
|
|
* then conversion back to quat gives a different result */
|
|
|
|
|
float quat[4];
|
|
|
|
|
normalize_qt_qt(quat, td->ext->quat);
|
|
|
|
|
quat_to_mat4(cob->matrix, quat);
|
|
|
|
|
}
|
|
|
|
|
else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
|
|
|
|
|
/* axis angle */
|
|
|
|
|
axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* eulers */
|
|
|
|
|
eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
static void constraintRotLim(const TransInfo *UNUSED(t), TransData *td)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
if (td->con) {
|
|
|
|
|
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
|
|
|
|
|
bConstraintOb cob;
|
|
|
|
|
bConstraint *con;
|
|
|
|
|
bool do_limit = false;
|
|
|
|
|
|
|
|
|
|
/* Evaluate valid constraints */
|
|
|
|
|
for (con = td->con; con; con = con->next) {
|
|
|
|
|
/* only consider constraint if enabled */
|
|
|
|
|
if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (con->enforce == 0.0f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we're only interested in Limit-Rotation constraints */
|
|
|
|
|
if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
|
|
|
|
|
bRotLimitConstraint *data = (bRotLimitConstraint *)con->data;
|
|
|
|
|
|
|
|
|
|
/* only use it if it's tagged for this purpose */
|
|
|
|
|
if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* skip incompatible spacetypes */
|
|
|
|
|
if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* only do conversion if necessary, to preserve quats and eulers */
|
|
|
|
|
if (do_limit == false) {
|
|
|
|
|
constraintob_from_transdata(&cob, td);
|
|
|
|
|
do_limit = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do space conversions */
|
|
|
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
|
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
|
|
|
mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do constraint */
|
|
|
|
|
cti->evaluate_constraint(con, &cob, NULL);
|
|
|
|
|
|
|
|
|
|
/* convert spaces again */
|
|
|
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
|
|
|
/* just multiply by td->smtx (this should be ok) */
|
|
|
|
|
mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (do_limit) {
|
|
|
|
|
/* copy results from cob->matrix */
|
|
|
|
|
if (td->ext->rotOrder == ROT_MODE_QUAT) {
|
|
|
|
|
/* quats */
|
|
|
|
|
mat4_to_quat(td->ext->quat, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
|
|
|
|
|
/* axis angle */
|
|
|
|
|
mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* eulers */
|
|
|
|
|
mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
void constraintSizeLim(const TransInfo *t, TransData *td)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
if (td->con && td->ext) {
|
|
|
|
|
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
|
|
|
|
|
bConstraintOb cob = {NULL};
|
|
|
|
|
bConstraint *con;
|
|
|
|
|
float size_sign[3], size_abs[3];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Make a temporary bConstraintOb for using these limit constraints
|
|
|
|
|
* - they only care that cob->matrix is correctly set ;-)
|
|
|
|
|
* - current space should be local
|
|
|
|
|
*/
|
|
|
|
|
if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
|
|
|
|
|
/* scale val and reset size */
|
|
|
|
|
return; /* TODO: fix this case */
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-03 17:25:04 +02:00
|
|
|
/* Reset val if SINGLESIZE but using a constraint */
|
|
|
|
|
if (td->flag & TD_SINGLESIZE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-02-14 08:42:17 -03:00
|
|
|
|
2020-07-03 17:25:04 +02:00
|
|
|
/* separate out sign to apply back later */
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
|
size_sign[i] = signf(td->ext->size[i]);
|
|
|
|
|
size_abs[i] = fabsf(td->ext->size[i]);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
|
2020-07-03 17:25:04 +02:00
|
|
|
size_to_mat4(cob.matrix, size_abs);
|
|
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
/* Evaluate valid constraints */
|
|
|
|
|
for (con = td->con; con; con = con->next) {
|
|
|
|
|
/* only consider constraint if enabled */
|
|
|
|
|
if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (con->enforce == 0.0f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we're only interested in Limit-Scale constraints */
|
|
|
|
|
if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
|
|
|
|
|
bSizeLimitConstraint *data = con->data;
|
|
|
|
|
|
|
|
|
|
/* only use it if it's tagged for this purpose */
|
|
|
|
|
if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do space conversions */
|
|
|
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
|
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
|
|
|
mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
|
|
|
|
|
/* skip... incompatible spacetype */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do constraint */
|
|
|
|
|
cti->evaluate_constraint(con, &cob, NULL);
|
|
|
|
|
|
|
|
|
|
/* convert spaces again */
|
|
|
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
|
|
|
/* just multiply by td->smtx (this should be ok) */
|
|
|
|
|
mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* copy results from cob->matrix */
|
|
|
|
|
if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
|
|
|
|
|
/* scale val and reset size */
|
|
|
|
|
return; /* TODO: fix this case. */
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-03 17:25:04 +02:00
|
|
|
/* Reset val if SINGLESIZE but using a constraint */
|
|
|
|
|
if (td->flag & TD_SINGLESIZE) {
|
|
|
|
|
return;
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
2020-07-03 17:25:04 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Extract scale from matrix and apply back sign. */
|
2020-07-03 17:25:04 +02:00
|
|
|
mat4_to_size(td->ext->size, cob.matrix);
|
|
|
|
|
mul_v3_v3(td->ext->size, size_sign);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-14 15:49:31 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
/* -------------------------------------------------------------------- */
|
2020-03-04 21:45:40 +11:00
|
|
|
/** \name Transform (Rotation Utils)
|
2020-02-14 08:42:17 -03:00
|
|
|
* \{ */
|
2021-12-14 15:49:31 +11:00
|
|
|
|
2021-05-27 02:23:19 +10:00
|
|
|
void headerRotation(TransInfo *t, char *str, const int str_size, float final)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
size_t ofs = 0;
|
|
|
|
|
|
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
|
|
|
char c[NUM_STR_REP_LEN];
|
|
|
|
|
|
|
|
|
|
outputNumInput(&(t->num), c, &t->scene->unit);
|
|
|
|
|
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(
|
2021-05-27 02:23:19 +10:00
|
|
|
str + ofs, str_size - ofs, TIP_("Rotation: %s %s %s"), &c[0], t->con.text, t->proptext);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
else {
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(str + ofs,
|
|
|
|
|
str_size - ofs,
|
|
|
|
|
TIP_("Rotation: %.2f%s %s"),
|
|
|
|
|
RAD2DEGF(final),
|
|
|
|
|
t->con.text,
|
|
|
|
|
t->proptext);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t->flag & T_PROP_EDIT_ALL) {
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(
|
|
|
|
|
str + ofs, str_size - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
void ElementRotation_ex(const TransInfo *t,
|
|
|
|
|
const TransDataContainer *tc,
|
2020-02-14 08:42:17 -03:00
|
|
|
TransData *td,
|
|
|
|
|
const float mat[3][3],
|
|
|
|
|
const float *center)
|
|
|
|
|
{
|
|
|
|
|
float vec[3], totmat[3][3], smat[3][3];
|
|
|
|
|
float eul[3], fmat[3][3], quat[4];
|
|
|
|
|
|
|
|
|
|
if (t->flag & T_POINTS) {
|
|
|
|
|
mul_m3_m3m3(totmat, mat, td->mtx);
|
|
|
|
|
mul_m3_m3m3(smat, td->smtx, totmat);
|
|
|
|
|
|
|
|
|
|
/* apply gpencil falloff */
|
|
|
|
|
if (t->options & CTX_GPENCIL_STROKES) {
|
|
|
|
|
bGPDstroke *gps = (bGPDstroke *)td->extra;
|
|
|
|
|
float sx = smat[0][0];
|
|
|
|
|
float sy = smat[1][1];
|
|
|
|
|
float sz = smat[2][2];
|
|
|
|
|
|
|
|
|
|
mul_m3_fl(smat, gps->runtime.multi_frame_falloff);
|
|
|
|
|
/* fix scale */
|
|
|
|
|
smat[0][0] = sx;
|
|
|
|
|
smat[1][1] = sy;
|
|
|
|
|
smat[2][2] = sz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub_v3_v3v3(vec, td->iloc, center);
|
|
|
|
|
mul_m3_v3(smat, vec);
|
|
|
|
|
|
|
|
|
|
add_v3_v3v3(td->loc, vec, center);
|
|
|
|
|
|
|
|
|
|
sub_v3_v3v3(vec, td->loc, td->iloc);
|
|
|
|
|
protectedTransBits(td->protectflag, vec);
|
|
|
|
|
add_v3_v3v3(td->loc, td->iloc, vec);
|
|
|
|
|
|
|
|
|
|
if (td->flag & TD_USEQUAT) {
|
|
|
|
|
mul_m3_series(fmat, td->smtx, mat, td->mtx);
|
|
|
|
|
mat3_to_quat(quat, fmat); /* Actual transform */
|
|
|
|
|
|
|
|
|
|
if (td->ext->quat) {
|
|
|
|
|
mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
|
|
|
|
|
|
|
|
|
|
/* is there a reason not to have this here? -jahka */
|
|
|
|
|
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* HACK WARNING
|
|
|
|
|
*
|
|
|
|
|
* This is some VERY ugly special case to deal with pose mode.
|
|
|
|
|
*
|
|
|
|
|
* The problem is that mtx and smtx include each bone orientation.
|
|
|
|
|
*
|
|
|
|
|
* That is needed to rotate each bone properly, HOWEVER, to calculate
|
|
|
|
|
* the translation component, we only need the actual armature object's
|
|
|
|
|
* matrix (and inverse). That is not all though. Once the proper translation
|
|
|
|
|
* has been computed, it has to be converted back into the bone's space.
|
|
|
|
|
*/
|
2021-02-05 11:56:43 -03:00
|
|
|
else if (t->options & CTX_POSE_BONE) {
|
2020-02-14 08:42:17 -03:00
|
|
|
/* Extract and invert armature object matrix */
|
|
|
|
|
|
|
|
|
|
if ((td->flag & TD_NO_LOC) == 0) {
|
|
|
|
|
sub_v3_v3v3(vec, td->center, center);
|
|
|
|
|
|
|
|
|
|
mul_m3_v3(tc->mat3, vec); /* To Global space. */
|
|
|
|
|
mul_m3_v3(mat, vec); /* Applying rotation. */
|
|
|
|
|
mul_m3_v3(tc->imat3, vec); /* To Local space. */
|
|
|
|
|
|
|
|
|
|
add_v3_v3(vec, center);
|
|
|
|
|
/* vec now is the location where the object has to be */
|
|
|
|
|
|
|
|
|
|
sub_v3_v3v3(vec, vec, td->center); /* Translation needed from the initial location */
|
|
|
|
|
|
|
|
|
|
/* special exception, see TD_PBONE_LOCAL_MTX definition comments */
|
|
|
|
|
if (td->flag & TD_PBONE_LOCAL_MTX_P) {
|
|
|
|
|
/* do nothing */
|
|
|
|
|
}
|
|
|
|
|
else if (td->flag & TD_PBONE_LOCAL_MTX_C) {
|
|
|
|
|
mul_m3_v3(tc->mat3, vec); /* To Global space. */
|
|
|
|
|
mul_m3_v3(td->ext->l_smtx, vec); /* To Pose space (Local Location). */
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mul_m3_v3(tc->mat3, vec); /* To Global space. */
|
|
|
|
|
mul_m3_v3(td->smtx, vec); /* To Pose space. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protectedTransBits(td->protectflag, vec);
|
|
|
|
|
|
|
|
|
|
add_v3_v3v3(td->loc, td->iloc, vec);
|
|
|
|
|
|
|
|
|
|
constraintTransLim(t, td);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* rotation */
|
|
|
|
|
/* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same,
|
|
|
|
|
* and ElementRotation() might be called in Translation context (with align snapping),
|
|
|
|
|
* we need to be sure to actually use the *rotation* matrix here...
|
|
|
|
|
* So no other way than storing it in some dedicated members of td->ext! */
|
|
|
|
|
if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */
|
|
|
|
|
/* euler or quaternion/axis-angle? */
|
|
|
|
|
if (td->ext->rotOrder == ROT_MODE_QUAT) {
|
|
|
|
|
mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
|
|
|
|
|
|
|
|
|
|
mat3_to_quat(quat, fmat); /* Actual transform */
|
|
|
|
|
|
|
|
|
|
mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
|
|
|
|
|
/* this function works on end result */
|
|
|
|
|
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
|
|
|
|
|
}
|
|
|
|
|
else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
|
|
|
|
|
/* calculate effect based on quats */
|
|
|
|
|
float iquat[4], tquat[4];
|
|
|
|
|
|
|
|
|
|
axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
|
|
|
|
|
|
|
|
|
|
mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
|
|
|
|
|
mat3_to_quat(quat, fmat); /* Actual transform */
|
|
|
|
|
mul_qt_qtqt(tquat, quat, iquat);
|
|
|
|
|
|
|
|
|
|
quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
|
|
|
|
|
|
|
|
|
|
/* this function works on end result */
|
|
|
|
|
protectedAxisAngleBits(td->protectflag,
|
|
|
|
|
td->ext->rotAxis,
|
|
|
|
|
td->ext->rotAngle,
|
|
|
|
|
td->ext->irotAxis,
|
|
|
|
|
td->ext->irotAngle);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
float eulmat[3][3];
|
|
|
|
|
|
|
|
|
|
mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
|
|
|
|
|
mul_m3_m3m3(smat, td->ext->r_smtx, totmat);
|
|
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Calculate the total rotation in eulers. */
|
2020-02-14 08:42:17 -03:00
|
|
|
copy_v3_v3(eul, td->ext->irot);
|
|
|
|
|
eulO_to_mat3(eulmat, eul, td->ext->rotOrder);
|
|
|
|
|
|
|
|
|
|
/* mat = transform, obmat = bone rotation */
|
|
|
|
|
mul_m3_m3m3(fmat, smat, eulmat);
|
|
|
|
|
|
|
|
|
|
mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
|
|
|
|
|
|
|
|
|
|
/* and apply (to end result only) */
|
|
|
|
|
protectedRotateBits(td->protectflag, eul, td->ext->irot);
|
|
|
|
|
copy_v3_v3(td->ext->rot, eul);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraintRotLim(t, td);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if ((td->flag & TD_NO_LOC) == 0) {
|
|
|
|
|
/* translation */
|
|
|
|
|
sub_v3_v3v3(vec, td->center, center);
|
|
|
|
|
mul_m3_v3(mat, vec);
|
|
|
|
|
add_v3_v3(vec, center);
|
|
|
|
|
/* vec now is the location where the object has to be */
|
|
|
|
|
sub_v3_v3(vec, td->center);
|
|
|
|
|
mul_m3_v3(td->smtx, vec);
|
|
|
|
|
|
|
|
|
|
protectedTransBits(td->protectflag, vec);
|
|
|
|
|
|
|
|
|
|
add_v3_v3v3(td->loc, td->iloc, vec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraintTransLim(t, td);
|
|
|
|
|
|
|
|
|
|
/* rotation */
|
|
|
|
|
if ((t->flag & T_V3D_ALIGN) == 0) { /* Align mode doesn't rotate objects itself. */
|
|
|
|
|
/* euler or quaternion? */
|
|
|
|
|
if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
|
|
|
|
|
/* can be called for texture space translate for example, then opt out */
|
|
|
|
|
if (td->ext->quat) {
|
|
|
|
|
mul_m3_series(fmat, td->smtx, mat, td->mtx);
|
2021-06-21 14:24:23 -03:00
|
|
|
|
|
|
|
|
if (!is_zero_v3(td->ext->dquat)) {
|
|
|
|
|
/* Correct for delta quat */
|
|
|
|
|
float tmp_mat[3][3];
|
|
|
|
|
quat_to_mat3(tmp_mat, td->ext->dquat);
|
|
|
|
|
mul_m3_m3m3(fmat, fmat, tmp_mat);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
mat3_to_quat(quat, fmat); /* Actual transform */
|
|
|
|
|
|
2021-06-21 14:24:23 -03:00
|
|
|
if (!is_zero_v4(td->ext->dquat)) {
|
|
|
|
|
/* Correct back for delta quat. */
|
|
|
|
|
float idquat[4];
|
|
|
|
|
invert_qt_qt_normalized(idquat, td->ext->dquat);
|
|
|
|
|
mul_qt_qtqt(quat, idquat, quat);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
|
2021-06-21 14:24:23 -03:00
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
/* this function works on end result */
|
|
|
|
|
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
|
|
|
|
|
/* calculate effect based on quats */
|
|
|
|
|
float iquat[4], tquat[4];
|
|
|
|
|
|
|
|
|
|
axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
|
|
|
|
|
|
|
|
|
|
mul_m3_series(fmat, td->smtx, mat, td->mtx);
|
|
|
|
|
mat3_to_quat(quat, fmat); /* Actual transform */
|
|
|
|
|
mul_qt_qtqt(tquat, quat, iquat);
|
|
|
|
|
|
|
|
|
|
quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
|
|
|
|
|
|
|
|
|
|
/* this function works on end result */
|
|
|
|
|
protectedAxisAngleBits(td->protectflag,
|
|
|
|
|
td->ext->rotAxis,
|
|
|
|
|
td->ext->rotAngle,
|
|
|
|
|
td->ext->irotAxis,
|
|
|
|
|
td->ext->irotAngle);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2021-06-21 14:24:23 -03:00
|
|
|
/* Calculate the total rotation in eulers. */
|
2020-02-14 08:42:17 -03:00
|
|
|
float obmat[3][3];
|
|
|
|
|
|
|
|
|
|
mul_m3_m3m3(totmat, mat, td->mtx);
|
|
|
|
|
mul_m3_m3m3(smat, td->smtx, totmat);
|
|
|
|
|
|
2021-06-21 14:24:23 -03:00
|
|
|
if (!is_zero_v3(td->ext->drot)) {
|
|
|
|
|
/* Correct for delta rot */
|
|
|
|
|
add_eul_euleul(eul, td->ext->irot, td->ext->drot, td->ext->rotOrder);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(eul, td->ext->irot);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
eulO_to_mat3(obmat, eul, td->ext->rotOrder);
|
|
|
|
|
mul_m3_m3m3(fmat, smat, obmat);
|
|
|
|
|
mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
|
|
|
|
|
|
2021-06-21 14:24:23 -03:00
|
|
|
if (!is_zero_v3(td->ext->drot)) {
|
|
|
|
|
/* Correct back for delta rot. */
|
|
|
|
|
sub_eul_euleul(eul, eul, td->ext->drot, td->ext->rotOrder);
|
|
|
|
|
}
|
2020-02-14 08:42:17 -03:00
|
|
|
|
|
|
|
|
/* and apply */
|
|
|
|
|
protectedRotateBits(td->protectflag, eul, td->ext->irot);
|
|
|
|
|
copy_v3_v3(td->ext->rot, eul);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraintRotLim(t, td);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
void ElementRotation(const TransInfo *t,
|
|
|
|
|
const TransDataContainer *tc,
|
|
|
|
|
TransData *td,
|
|
|
|
|
const float mat[3][3],
|
|
|
|
|
const short around)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
const float *center;
|
|
|
|
|
|
|
|
|
|
/* local constraint shouldn't alter center */
|
|
|
|
|
if (transdata_check_local_center(t, around)) {
|
|
|
|
|
center = td->center;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
center = tc->center_local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ElementRotation_ex(t, tc, td, mat, center);
|
|
|
|
|
}
|
2021-12-14 15:49:31 +11:00
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Transform (Resize Utils)
|
|
|
|
|
* \{ */
|
2021-12-09 00:55:11 +11:00
|
|
|
|
2021-05-27 02:23:19 +10:00
|
|
|
void headerResize(TransInfo *t, const float vec[3], char *str, const int str_size)
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
char tvec[NUM_STR_REP_LEN * 3];
|
|
|
|
|
size_t ofs = 0;
|
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
|
|
|
outputNumInput(&(t->num), tvec, &t->scene->unit);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
|
|
|
|
|
BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
|
|
|
|
|
BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t->con.mode & CON_APPLY) {
|
|
|
|
|
switch (t->num.idx_max) {
|
|
|
|
|
case 0:
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(
|
2021-05-27 02:23:19 +10:00
|
|
|
str + ofs, str_size - ofs, TIP_("Scale: %s%s %s"), &tvec[0], t->con.text, t->proptext);
|
2020-02-14 08:42:17 -03:00
|
|
|
break;
|
|
|
|
|
case 1:
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(str + ofs,
|
|
|
|
|
str_size - ofs,
|
|
|
|
|
TIP_("Scale: %s : %s%s %s"),
|
|
|
|
|
&tvec[0],
|
|
|
|
|
&tvec[NUM_STR_REP_LEN],
|
|
|
|
|
t->con.text,
|
|
|
|
|
t->proptext);
|
2020-02-14 08:42:17 -03:00
|
|
|
break;
|
|
|
|
|
case 2:
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(str + ofs,
|
|
|
|
|
str_size - ofs,
|
|
|
|
|
TIP_("Scale: %s : %s : %s%s %s"),
|
|
|
|
|
&tvec[0],
|
|
|
|
|
&tvec[NUM_STR_REP_LEN],
|
|
|
|
|
&tvec[NUM_STR_REP_LEN * 2],
|
|
|
|
|
t->con.text,
|
|
|
|
|
t->proptext);
|
2020-02-14 08:42:17 -03:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (t->flag & T_2D_EDIT) {
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(str + ofs,
|
|
|
|
|
str_size - ofs,
|
|
|
|
|
TIP_("Scale X: %s Y: %s%s %s"),
|
|
|
|
|
&tvec[0],
|
|
|
|
|
&tvec[NUM_STR_REP_LEN],
|
|
|
|
|
t->con.text,
|
|
|
|
|
t->proptext);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
else {
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(str + ofs,
|
|
|
|
|
str_size - ofs,
|
|
|
|
|
TIP_("Scale X: %s Y: %s Z: %s%s %s"),
|
|
|
|
|
&tvec[0],
|
|
|
|
|
&tvec[NUM_STR_REP_LEN],
|
|
|
|
|
&tvec[NUM_STR_REP_LEN * 2],
|
|
|
|
|
t->con.text,
|
|
|
|
|
t->proptext);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t->flag & T_PROP_EDIT_ALL) {
|
2021-05-27 17:16:08 +10:00
|
|
|
ofs += BLI_snprintf_rlen(
|
|
|
|
|
str + ofs, str_size - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \a smat is reference matrix only.
|
|
|
|
|
*
|
|
|
|
|
* \note this is a tricky area, before making changes see: T29633, T42444
|
|
|
|
|
*/
|
2020-08-07 22:56:13 +10:00
|
|
|
static void TransMat3ToSize(const float mat[3][3], const float smat[3][3], float size[3])
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
float rmat[3][3];
|
|
|
|
|
|
|
|
|
|
mat3_to_rot_size(rmat, size, mat);
|
|
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* First tried with dot-product... but the sign flip is crucial. */
|
2020-02-14 08:42:17 -03:00
|
|
|
if (dot_v3v3(rmat[0], smat[0]) < 0.0f) {
|
|
|
|
|
size[0] = -size[0];
|
|
|
|
|
}
|
|
|
|
|
if (dot_v3v3(rmat[1], smat[1]) < 0.0f) {
|
|
|
|
|
size[1] = -size[1];
|
|
|
|
|
}
|
|
|
|
|
if (dot_v3v3(rmat[2], smat[2]) < 0.0f) {
|
|
|
|
|
size[2] = -size[2];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
void ElementResize(const TransInfo *t,
|
|
|
|
|
const TransDataContainer *tc,
|
|
|
|
|
TransData *td,
|
|
|
|
|
const float mat[3][3])
|
2020-02-14 08:42:17 -03:00
|
|
|
{
|
|
|
|
|
float tmat[3][3], smat[3][3], center[3];
|
|
|
|
|
float vec[3];
|
|
|
|
|
|
|
|
|
|
if (t->flag & T_EDIT) {
|
|
|
|
|
mul_m3_m3m3(smat, mat, td->mtx);
|
|
|
|
|
mul_m3_m3m3(tmat, td->smtx, smat);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_m3_m3(tmat, mat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t->con.applySize) {
|
|
|
|
|
t->con.applySize(t, tc, td, tmat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* local constraint shouldn't alter center */
|
|
|
|
|
if (transdata_check_local_center(t, t->around)) {
|
|
|
|
|
copy_v3_v3(center, td->center);
|
|
|
|
|
}
|
|
|
|
|
else if (t->options & CTX_MOVIECLIP) {
|
|
|
|
|
if (td->flag & TD_INDIVIDUAL_SCALE) {
|
|
|
|
|
copy_v3_v3(center, td->center);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(center, tc->center_local);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(center, tc->center_local);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Size checked needed since the 3D cursor only uses rotation fields. */
|
|
|
|
|
if (td->ext && td->ext->size) {
|
|
|
|
|
float fsize[3];
|
|
|
|
|
|
2020-06-10 16:36:07 -03:00
|
|
|
if (ELEM(t->data_type, TC_SCULPT, TC_OBJECT, TC_OBJECT_TEXSPACE, TC_POSE)) {
|
2020-02-14 08:42:17 -03:00
|
|
|
float obsizemat[3][3];
|
|
|
|
|
/* Reorient the size mat to fit the oriented object. */
|
|
|
|
|
mul_m3_m3m3(obsizemat, tmat, td->axismtx);
|
2021-08-12 14:34:41 +10:00
|
|
|
// print_m3("obsizemat", obsizemat);
|
2020-02-14 08:42:17 -03:00
|
|
|
TransMat3ToSize(obsizemat, td->axismtx, fsize);
|
2021-08-12 14:34:41 +10:00
|
|
|
// print_v3("fsize", fsize);
|
2020-02-14 08:42:17 -03:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mat3_to_size(fsize, tmat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protectedSizeBits(td->protectflag, fsize);
|
|
|
|
|
|
|
|
|
|
if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't resize objects itself */
|
|
|
|
|
if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
|
|
|
|
|
/* scale val and reset size */
|
|
|
|
|
*td->val = td->ival * (1 + (fsize[0] - 1) * td->factor);
|
|
|
|
|
|
|
|
|
|
td->ext->size[0] = td->ext->isize[0];
|
|
|
|
|
td->ext->size[1] = td->ext->isize[1];
|
|
|
|
|
td->ext->size[2] = td->ext->isize[2];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Reset val if SINGLESIZE but using a constraint */
|
|
|
|
|
if (td->flag & TD_SINGLESIZE) {
|
|
|
|
|
*td->val = td->ival;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
td->ext->size[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
|
|
|
|
|
td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
|
|
|
|
|
td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraintSizeLim(t, td);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For individual element center, Editmode need to use iloc */
|
|
|
|
|
if (t->flag & T_POINTS) {
|
|
|
|
|
sub_v3_v3v3(vec, td->iloc, center);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
sub_v3_v3v3(vec, td->center, center);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mul_m3_v3(tmat, vec);
|
|
|
|
|
|
|
|
|
|
add_v3_v3(vec, center);
|
|
|
|
|
if (t->flag & T_POINTS) {
|
|
|
|
|
sub_v3_v3(vec, td->iloc);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
sub_v3_v3(vec, td->center);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
/* Grease pencil falloff.
|
|
|
|
|
*
|
|
|
|
|
* FIXME: This is bad on multiple levels!
|
|
|
|
|
*
|
|
|
|
|
* - #applyNumInput is not intended to be run for every element,
|
|
|
|
|
* this writes back into the number input in a way that doesn't make sense to run many times.
|
|
|
|
|
*
|
|
|
|
|
* - Writing into #TransInfo should be avoided since it means order of operations
|
|
|
|
|
* may impact the result and isn't thread-safe.
|
|
|
|
|
*
|
|
|
|
|
* Operating on copies as a temporary solution.
|
|
|
|
|
*/
|
2020-02-14 08:42:17 -03:00
|
|
|
if (t->options & CTX_GPENCIL_STROKES) {
|
|
|
|
|
bGPDstroke *gps = (bGPDstroke *)td->extra;
|
|
|
|
|
mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
|
|
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
/* Scale stroke thickness. */
|
2020-02-14 08:42:17 -03:00
|
|
|
if (td->val) {
|
2021-06-29 20:13:55 +10:00
|
|
|
NumInput num_evil = t->num;
|
|
|
|
|
float values_final_evil[4];
|
|
|
|
|
copy_v4_v4(values_final_evil, t->values_final);
|
|
|
|
|
transform_snap_increment(t, values_final_evil);
|
|
|
|
|
applyNumInput(&num_evil, values_final_evil);
|
2020-02-14 08:42:17 -03:00
|
|
|
|
2021-06-29 20:13:55 +10:00
|
|
|
float ratio = values_final_evil[0];
|
2021-12-30 11:17:55 +01:00
|
|
|
*td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff;
|
2020-02-14 08:42:17 -03:00
|
|
|
CLAMP_MIN(*td->val, 0.001f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mul_v3_fl(vec, td->factor);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-05 11:56:43 -03:00
|
|
|
if (t->options & (CTX_OBJECT | CTX_POSE_BONE)) {
|
2021-11-03 11:14:22 +11:00
|
|
|
if (t->options & CTX_POSE_BONE) {
|
|
|
|
|
/* Without this, the resulting location of scaled bones aren't correct,
|
|
|
|
|
* especially noticeable scaling root or disconnected bones around the cursor, see T92515. */
|
|
|
|
|
mul_mat3_m4_v3(tc->poseobj->obmat, vec);
|
|
|
|
|
}
|
2020-02-14 08:42:17 -03:00
|
|
|
mul_m3_v3(td->smtx, vec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protectedTransBits(td->protectflag, vec);
|
|
|
|
|
if (td->loc) {
|
|
|
|
|
add_v3_v3v3(td->loc, td->iloc, vec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraintTransLim(t, td);
|
|
|
|
|
}
|
2021-06-29 20:13:55 +10:00
|
|
|
|
2020-02-14 08:42:17 -03:00
|
|
|
/** \} */
|
|
|
|
|
|
2020-02-21 10:42:56 -03:00
|
|
|
/* -------------------------------------------------------------------- */
|
2020-03-25 16:36:01 +11:00
|
|
|
/** \name Transform Mode Initialization
|
2020-02-21 10:42:56 -03:00
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
|
|
|
|
|
{
|
|
|
|
|
t->mode = mode;
|
|
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case TFM_TRANSLATION:
|
|
|
|
|
initTranslation(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_ROTATION:
|
|
|
|
|
initRotation(t);
|
|
|
|
|
break;
|
2021-10-08 12:09:27 +02:00
|
|
|
case TFM_RESIZE: {
|
|
|
|
|
float mouse_dir_constraint[3];
|
|
|
|
|
if (op) {
|
2021-11-02 23:31:19 +11:00
|
|
|
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "mouse_dir_constraint");
|
|
|
|
|
if (prop) {
|
|
|
|
|
RNA_property_float_get_array(op->ptr, prop, mouse_dir_constraint);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Resize is expected to have this property. */
|
|
|
|
|
BLI_assert(!STREQ(op->idname, "TRANSFORM_OT_resize"));
|
|
|
|
|
}
|
2021-10-08 12:09:27 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
zero_v3(mouse_dir_constraint);
|
|
|
|
|
}
|
|
|
|
|
initResize(t, mouse_dir_constraint);
|
2020-02-21 10:42:56 -03:00
|
|
|
break;
|
2021-10-08 12:09:27 +02:00
|
|
|
}
|
2020-02-21 10:42:56 -03:00
|
|
|
case TFM_SKIN_RESIZE:
|
|
|
|
|
initSkinResize(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TOSPHERE:
|
|
|
|
|
initToSphere(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_SHEAR:
|
|
|
|
|
initShear(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_BEND:
|
|
|
|
|
initBend(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_SHRINKFATTEN:
|
|
|
|
|
initShrinkFatten(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TILT:
|
|
|
|
|
initTilt(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_CURVE_SHRINKFATTEN:
|
|
|
|
|
initCurveShrinkFatten(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_MASK_SHRINKFATTEN:
|
|
|
|
|
initMaskShrinkFatten(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_GPENCIL_SHRINKFATTEN:
|
|
|
|
|
initGPShrinkFatten(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TRACKBALL:
|
|
|
|
|
initTrackball(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_PUSHPULL:
|
|
|
|
|
initPushPull(t);
|
|
|
|
|
break;
|
Subdivision: add support for vertex creasing
This adds vertex creasing support for OpenSubDiv for modeling, rendering,
Alembic and USD I/O.
For modeling, vertex creasing follows the edge creasing implementation with an
operator accessible through the Vertex menu in Edit Mode, and some parameter in
the properties panel. The option in the Subsurf and Multires to use edge
creasing also affects vertex creasing.
The vertex crease data is stored as a CustomData layer, unlike edge creases
which for now are stored in `MEdge`, but will in the future also be moved to
a `CustomData` layer. See comments for details on the difference in behavior
for the `CD_CREASE` layer between egdes and vertices.
For Cycles this adds sockets on the Mesh node to hold data about which vertices
are creased (one socket for the indices, one for the weigths).
Viewport rendering of vertex creasing reuses the same color scheme as for edges
and creased vertices are drawn bigger than uncreased vertices.
For Alembic and USD, vertex crease support follows the edge crease
implementation, they are always read, but only exported if a `Subsurf` modifier
is present on the Mesh.
Reviewed By: brecht, fclem, sergey, sybren, campbellbarton
Differential Revision: https://developer.blender.org/D10145
2022-01-20 12:20:30 +01:00
|
|
|
case TFM_EDGE_CREASE:
|
|
|
|
|
initEgdeCrease(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_VERT_CREASE:
|
|
|
|
|
initVertCrease(t);
|
2020-02-21 10:42:56 -03:00
|
|
|
break;
|
2020-06-22 19:06:04 -03:00
|
|
|
case TFM_BONESIZE:
|
|
|
|
|
initBoneSize(t);
|
2020-02-21 10:42:56 -03:00
|
|
|
break;
|
|
|
|
|
case TFM_BONE_ENVELOPE:
|
|
|
|
|
case TFM_BONE_ENVELOPE_DIST:
|
|
|
|
|
initBoneEnvelope(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_EDGE_SLIDE:
|
|
|
|
|
case TFM_VERT_SLIDE: {
|
|
|
|
|
const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false);
|
|
|
|
|
const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false);
|
|
|
|
|
const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true);
|
|
|
|
|
if (mode == TFM_EDGE_SLIDE) {
|
|
|
|
|
const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
|
|
|
|
|
initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
initVertSlide_ex(t, use_even, flipped, use_clamp);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TFM_BONE_ROLL:
|
|
|
|
|
initBoneRoll(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TIME_TRANSLATE:
|
|
|
|
|
initTimeTranslate(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TIME_SLIDE:
|
|
|
|
|
initTimeSlide(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TIME_SCALE:
|
|
|
|
|
initTimeScale(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TIME_DUPLICATE:
|
|
|
|
|
/* same as TFM_TIME_EXTEND, but we need the mode info for later
|
|
|
|
|
* so that duplicate-culling will work properly
|
|
|
|
|
*/
|
|
|
|
|
if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
|
|
|
|
|
initTranslation(t);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
initTimeTranslate(t);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TFM_TIME_EXTEND:
|
|
|
|
|
/* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
|
|
|
|
|
* Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
|
|
|
|
|
* (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement)
|
|
|
|
|
* depending on which editor this was called from
|
|
|
|
|
*/
|
|
|
|
|
if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
|
|
|
|
|
initTranslation(t);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
initTimeTranslate(t);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TFM_BAKE_TIME:
|
|
|
|
|
initBakeTime(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_MIRROR:
|
|
|
|
|
initMirror(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_BWEIGHT:
|
|
|
|
|
initBevelWeight(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_ALIGN:
|
|
|
|
|
initAlign(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_SEQ_SLIDE:
|
|
|
|
|
initSeqSlide(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_NORMAL_ROTATION:
|
|
|
|
|
initNormalRotation(t);
|
|
|
|
|
break;
|
|
|
|
|
case TFM_GPENCIL_OPACITY:
|
|
|
|
|
initGPOpacity(t);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-01 17:45:27 +10:00
|
|
|
if (t->data_type == TC_MESH_VERTS) {
|
|
|
|
|
/* Init Custom Data correction.
|
|
|
|
|
* Ideally this should be called when creating the TransData. */
|
2021-04-24 10:46:46 -03:00
|
|
|
transform_convert_mesh_customdatacorrect_init(t);
|
2020-07-01 17:45:27 +10:00
|
|
|
}
|
|
|
|
|
|
2020-02-21 10:42:56 -03:00
|
|
|
/* TODO(germano): Some of these operations change the `t->mode`.
|
2022-03-08 13:48:31 +11:00
|
|
|
* This can be bad for Redo. */
|
|
|
|
|
// BLI_assert(t->mode == mode);
|
2020-02-21 10:42:56 -03:00
|
|
|
}
|
|
|
|
|
|
2021-05-11 23:40:06 -03:00
|
|
|
void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
|
|
|
|
|
{
|
|
|
|
|
/* Currently only these types are supported. */
|
|
|
|
|
BLI_assert(ELEM(type, V3D_ORIENT_GLOBAL, V3D_ORIENT_VIEW));
|
|
|
|
|
|
2021-11-26 10:45:28 -03:00
|
|
|
if (t->is_orient_default_overwrite) {
|
2021-05-11 23:40:06 -03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(t->flag & T_MODAL)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (t->orient[O_DEFAULT].type == type) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 16:29:59 +10:00
|
|
|
View3D *v3d = NULL;
|
2021-05-11 23:40:06 -03:00
|
|
|
RegionView3D *rv3d = NULL;
|
|
|
|
|
if ((type == V3D_ORIENT_VIEW) && (t->spacetype == SPACE_VIEW3D) && t->region &&
|
|
|
|
|
(t->region->regiontype == RGN_TYPE_WINDOW)) {
|
2021-08-31 16:29:59 +10:00
|
|
|
v3d = t->view;
|
2021-05-11 23:40:06 -03:00
|
|
|
rv3d = t->region->regiondata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t->orient[O_DEFAULT].type = ED_transform_calc_orientation_from_type_ex(
|
2021-08-31 16:29:59 +10:00
|
|
|
t->scene,
|
|
|
|
|
t->view_layer,
|
|
|
|
|
v3d,
|
|
|
|
|
rv3d,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
type,
|
|
|
|
|
V3D_AROUND_CENTER_BOUNDS,
|
|
|
|
|
t->orient[O_DEFAULT].matrix);
|
2021-05-11 23:40:06 -03:00
|
|
|
|
|
|
|
|
if (t->orient_curr == O_DEFAULT) {
|
|
|
|
|
/* Update Orientation. */
|
|
|
|
|
transform_orientations_current_set(t, O_DEFAULT);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-14 15:49:31 +11:00
|
|
|
|
2020-02-21 10:42:56 -03:00
|
|
|
/** \} */
|