1475
/* ******************* TRANSFORM LIMITS ********************** */
1477
static void constraintTransLim(TransInfo *t, TransData *td)
1480
bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
1484
/* Make a temporary bConstraintOb for using these limit constraints
1485
* - they only care that cob->matrix is correctly set ;-)
1486
* - current space should be local
1488
memset(&cob, 0, sizeof(bConstraintOb));
1489
Mat4One(cob.matrix);
1491
TransDataIpokey *tdi= td->tdi;
1492
cob.matrix[3][0]= tdi->locx[0];
1493
cob.matrix[3][1]= tdi->locy[0];
1494
cob.matrix[3][2]= tdi->locz[0];
1497
VECCOPY(cob.matrix[3], td->loc);
1500
/* Evaluate valid constraints */
1501
for (con= td->con; con; con= con->next) {
1504
/* only use it if it's tagged for this purpose (and the right type) */
1505
if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
1506
bLocLimitConstraint *data= con->data;
1508
if ((data->flag2 & LIMIT_TRANSFORM)==0)
1511
/* do space conversions */
1512
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1513
/* just multiply by td->mtx (this should be ok) */
1514
Mat4CpyMat4(tmat, cob.matrix);
1515
Mat4MulMat34(cob.matrix, td->mtx, tmat);
1517
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1518
/* skip... incompatable spacetype */
1523
cti->evaluate_constraint(con, &cob, NULL);
1525
/* convert spaces again */
1526
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1527
/* just multiply by td->mtx (this should be ok) */
1528
Mat4CpyMat4(tmat, cob.matrix);
1529
Mat4MulMat34(cob.matrix, td->smtx, tmat);
1534
/* copy results from cob->matrix */
1536
TransDataIpokey *tdi= td->tdi;
1537
tdi->locx[0]= cob.matrix[3][0];
1538
tdi->locy[0]= cob.matrix[3][1];
1539
tdi->locz[0]= cob.matrix[3][2];
1542
VECCOPY(td->loc, cob.matrix[3]);
1547
static void constraintRotLim(TransInfo *t, TransData *td)
1550
bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
1554
/* Make a temporary bConstraintOb for using these limit constraints
1555
* - they only care that cob->matrix is correctly set ;-)
1556
* - current space should be local
1558
memset(&cob, 0, sizeof(bConstraintOb));
1559
if (td->flag & TD_USEQUAT) {
1562
QuatToMat4(td->ext->quat, cob.matrix);
1567
/* ipo-keys eulers */
1568
TransDataIpokey *tdi= td->tdi;
1571
eul[0]= tdi->rotx[0];
1572
eul[1]= tdi->roty[0];
1573
eul[2]= tdi->rotz[0];
1575
EulToMat4(eul, cob.matrix);
1580
EulToMat4(td->ext->rot, cob.matrix);
1585
/* Evaluate valid constraints */
1586
for (con= td->con; con; con= con->next) {
1587
/* we're only interested in Limit-Scale constraints */
1588
if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
1589
bRotLimitConstraint *data= con->data;
1592
/* only use it if it's tagged for this purpose */
1593
if ((data->flag2 & LIMIT_TRANSFORM)==0)
1596
/* do space conversions */
1597
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1598
/* just multiply by td->mtx (this should be ok) */
1599
Mat4CpyMat4(tmat, cob.matrix);
1600
Mat4MulMat34(cob.matrix, td->mtx, tmat);
1602
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1603
/* skip... incompatable spacetype */
1608
cti->evaluate_constraint(con, &cob, NULL);
1610
/* convert spaces again */
1611
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1612
/* just multiply by td->mtx (this should be ok) */
1613
Mat4CpyMat4(tmat, cob.matrix);
1614
Mat4MulMat34(cob.matrix, td->smtx, tmat);
1619
/* copy results from cob->matrix */
1620
if (td->flag & TD_USEQUAT) {
1622
Mat4ToQuat(cob.matrix, td->ext->quat);
1625
/* ipo-keys eulers */
1626
TransDataIpokey *tdi= td->tdi;
1629
Mat4ToEul(cob.matrix, eul);
1631
tdi->rotx[0]= eul[0];
1632
tdi->roty[0]= eul[1];
1633
tdi->rotz[0]= eul[2];
1637
Mat4ToEul(cob.matrix, td->ext->rot);
1642
static void constraintSizeLim(TransInfo *t, TransData *td)
1644
if (td->con && td->ext) {
1645
bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
1649
/* Make a temporary bConstraintOb for using these limit constraints
1650
* - they only care that cob->matrix is correctly set ;-)
1651
* - current space should be local
1653
memset(&cob, 0, sizeof(bConstraintOb));
1655
TransDataIpokey *tdi= td->tdi;
1658
size[0]= tdi->sizex[0];
1659
size[1]= tdi->sizey[0];
1660
size[2]= tdi->sizez[0];
1661
SizeToMat4(size, cob.matrix);
1663
else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1664
/* scale val and reset size */
1665
return; // TODO: fix this case
1668
/* Reset val if SINGLESIZE but using a constraint */
1669
if (td->flag & TD_SINGLESIZE)
1672
SizeToMat4(td->ext->size, cob.matrix);
1675
/* Evaluate valid constraints */
1676
for (con= td->con; con; con= con->next) {
1677
/* we're only interested in Limit-Scale constraints */
1678
if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
1679
bSizeLimitConstraint *data= con->data;
1682
/* only use it if it's tagged for this purpose */
1683
if ((data->flag2 & LIMIT_TRANSFORM)==0)
1686
/* do space conversions */
1687
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1688
/* just multiply by td->mtx (this should be ok) */
1689
Mat4CpyMat4(tmat, cob.matrix);
1690
Mat4MulMat34(cob.matrix, td->mtx, tmat);
1692
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1693
/* skip... incompatable spacetype */
1698
cti->evaluate_constraint(con, &cob, NULL);
1700
/* convert spaces again */
1701
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1702
/* just multiply by td->mtx (this should be ok) */
1703
Mat4CpyMat4(tmat, cob.matrix);
1704
Mat4MulMat34(cob.matrix, td->smtx, tmat);
1709
/* copy results from cob->matrix */
1711
TransDataIpokey *tdi= td->tdi;
1714
Mat4ToSize(cob.matrix, size);
1716
tdi->sizex[0]= size[0];
1717
tdi->sizey[0]= size[1];
1718
tdi->sizez[0]= size[2];
1720
else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1721
/* scale val and reset size */
1722
return; // TODO: fix this case
1725
/* Reset val if SINGLESIZE but using a constraint */
1726
if (td->flag & TD_SINGLESIZE)
1729
Mat4ToSize(cob.matrix, td->ext->size);
1099
1734
/* ************************** WARP *************************** */
1101
/* warp is done fully in view space */
1102
1736
void initWarp(TransInfo *t)
1104
1738
float max[3], min[3];
1107
calculateCenterCursor(t);
1110
1742
t->transform = Warp;
1743
t->handleEvent = handleEventWarp;
1111
1747
t->snap[0] = 0.0f;
1112
1748
t->snap[1] = 5.0f;
1113
1749
t->snap[2] = 1.0f;
1751
t->flag |= T_NO_CONSTRAINT;
1753
/* warp is done fully in view space */
1754
calculateCenterCursor(t);
1115
1755
t->fac = (float)(t->center2d[0] - t->imval[0]);
1117
1757
/* we need min/max in view space */
1687
2425
VecAddf(td->loc, vec, t->center);
2427
VecSubf(vec,td->loc,td->iloc);
2428
protectedTransBits(td->protectflag, vec);
2429
VecAddf(td->loc, td->iloc, vec);
1689
2431
if(td->flag & TD_USEQUAT) {
1690
2432
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1691
2433
Mat3ToQuat(fmat, quat); // Actual transform
2436
QuatMul(td->ext->quat, quat, td->ext->iquat);
2438
/* is there a reason not to have this here? -jahka */
2439
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2446
* This is some VERY ugly special case to deal with pose mode.
2448
* The problem is that mtx and smtx include each bone orientation.
2450
* That is needed to rotate each bone properly, HOWEVER, to calculate
2451
* the translation component, we only need the actual armature object's
2452
* matrix (and inverse). That is not all though. Once the proper translation
2453
* has been computed, it has to be converted back into the bone's space.
2455
else if (t->flag & T_POSE) {
2456
float pmtx[3][3], imtx[3][3];
2458
// Extract and invert armature object matrix
2459
Mat3CpyMat4(pmtx, t->poseobj->obmat);
2460
Mat3Inv(imtx, pmtx);
2462
VecSubf(vec, td->center, t->center);
2464
Mat3MulVecfl(pmtx, vec); // To Global space
2465
Mat3MulVecfl(mat, vec); // Applying rotation
2466
Mat3MulVecfl(imtx, vec); // To Local space
2468
VecAddf(vec, vec, t->center);
2469
/* vec now is the location where the object has to be */
2471
VecSubf(vec, vec, td->center); // Translation needed from the initial location
2473
Mat3MulVecfl(pmtx, vec); // To Global space
2474
Mat3MulVecfl(td->smtx, vec);// To Pose space
2476
protectedTransBits(td->protectflag, vec);
2478
VecAddf(td->loc, td->iloc, vec);
2480
constraintTransLim(t, td);
2483
if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2484
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2486
Mat3ToQuat(fmat, quat); // Actual transform
1692
2488
QuatMul(td->ext->quat, quat, td->ext->iquat);
2489
/* this function works on end result */
2490
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2492
constraintRotLim(t, td);
1696
2496
/* translation */
1698
2497
VecSubf(vec, td->center, t->center);
1699
2498
Mat3MulVecfl(mat, vec);
1700
2499
VecAddf(vec, vec, t->center);
1701
2500
/* vec now is the location where the object has to be */
1702
2501
VecSubf(vec, vec, td->center);
1703
2502
Mat3MulVecfl(td->smtx, vec);
1705
2504
protectedTransBits(td->protectflag, vec);
1708
2507
TransDataIpokey *tdi= td->tdi;
1709
2508
add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1711
2510
add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1713
2512
else VecAddf(td->loc, td->iloc, vec);
2514
constraintTransLim(t, td);
1717
if(td->flag & TD_USEQUAT) {
1718
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1719
Mat3ToQuat(fmat, quat); // Actual transform
1721
QuatMul(td->ext->quat, quat, td->ext->iquat);
1722
/* this function works on end result */
1723
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
1725
else if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
1728
/* are there ipo keys? */
1730
TransDataIpokey *tdi= td->tdi;
1733
/* calculate the total rotatation in eulers */
1734
VecAddf(eul, td->ext->irot, td->ext->drot);
1735
EulToMat3(eul, obmat);
1736
/* mat = transform, obmat = object rotation */
1737
Mat3MulMat3(fmat, mat, obmat);
1738
Mat3ToEul(fmat, eul);
1739
compatible_eul(eul, td->ext->irot);
1741
/* correct back for delta rot */
1742
if(tdi->flag & TOB_IPODROT) {
1743
VecSubf(rot, eul, td->ext->irot);
2517
if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2518
if(td->flag & TD_USEQUAT) {
2519
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2520
Mat3ToQuat(fmat, quat); // Actual transform
2522
QuatMul(td->ext->quat, quat, td->ext->iquat);
2523
/* this function works on end result */
2524
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2529
/* are there ipo keys? */
2531
TransDataIpokey *tdi= td->tdi;
2534
/* calculate the total rotatation in eulers */
2535
VecAddf(eul, td->ext->irot, td->ext->drot);
2536
EulToMat3(eul, obmat);
2537
/* mat = transform, obmat = object rotation */
2538
Mat3MulMat3(fmat, mat, obmat);
2540
Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2542
/* correct back for delta rot */
2543
if(tdi->flag & TOB_IPODROT) {
2544
VecSubf(rot, eul, td->ext->irot);
2547
VecSubf(rot, eul, td->ext->drot);
2550
VecMulf(rot, (float)(9.0/M_PI_2));
2551
VecSubf(rot, rot, tdi->oldrot);
2553
protectedRotateBits(td->protectflag, rot, tdi->oldrot);
2555
add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2556
add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2557
add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1746
VecSubf(rot, eul, td->ext->drot);
2560
Mat3MulMat3(totmat, mat, td->mtx);
2561
Mat3MulMat3(smat, td->smtx, totmat);
2563
/* calculate the total rotatation in eulers */
2564
VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2565
EulToMat3(eul, obmat);
2566
/* mat = transform, obmat = object rotation */
2567
Mat3MulMat3(fmat, smat, obmat);
2569
Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2571
/* correct back for delta rot */
2572
VecSubf(eul, eul, td->ext->drot);
2575
protectedRotateBits(td->protectflag, eul, td->ext->irot);
2576
VECCOPY(td->ext->rot, eul);
1749
VecMulf(rot, (float)(9.0/M_PI_2));
1750
VecSubf(rot, rot, tdi->oldrot);
1752
protectedRotateBits(td->protectflag, rot, tdi->oldrot);
1754
add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
1755
add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
1756
add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1759
Mat3MulMat3(totmat, mat, td->mtx);
1760
Mat3MulMat3(smat, td->smtx, totmat);
1762
/* calculate the total rotatation in eulers */
1763
VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
1764
EulToMat3(eul, obmat);
1765
/* mat = transform, obmat = object rotation */
1766
Mat3MulMat3(fmat, smat, obmat);
1767
Mat3ToEul(fmat, eul);
1768
compatible_eul(eul, td->ext->irot);
1770
/* correct back for delta rot */
1771
VecSubf(eul, eul, td->ext->drot);
1774
protectedRotateBits(td->protectflag, eul, td->ext->irot);
1775
VECCOPY(td->ext->rot, eul);
2580
constraintRotLim(t, td);
3345
/* ************************** BEVEL **************************** */
3347
void initBevel(TransInfo *t)
3349
t->mode = TFM_BEVEL;
3350
t->flag |= T_NO_CONSTRAINT;
3351
t->transform = Bevel;
3352
t->handleEvent = handleEventBevel;
3353
if (G.editBMesh->imval[0] == 0 && G.editBMesh->imval[1] == 0) {
3354
/* save the initial mouse co */
3355
G.editBMesh->imval[0] = t->imval[0];
3356
G.editBMesh->imval[1] = t->imval[1];
3359
/* restore the mouse co from a previous call to initTransform() */
3360
t->imval[0] = G.editBMesh->imval[0];
3361
t->imval[1] = G.editBMesh->imval[1];
3365
int handleEventBevel(TransInfo *t, unsigned short event, short val)
3368
if(!G.editBMesh) return 0;
3372
G.editBMesh->options ^= BME_BEVEL_VERT;
3373
t->state = TRANS_CANCEL;
3376
// G.editBMesh->options ^= BME_BEVEL_RES;
3377
// G.editBMesh->res += 1;
3378
// if (G.editBMesh->res > 4) {
3379
// G.editBMesh->res = 4;
3381
// t->state = TRANS_CANCEL;
3384
// G.editBMesh->options ^= BME_BEVEL_RES;
3385
// G.editBMesh->res -= 1;
3386
// if (G.editBMesh->res < 0) {
3387
// G.editBMesh->res = 0;
3389
// t->state = TRANS_CANCEL;
3398
int Bevel(TransInfo *t, short mval[2])
3404
TransData *td = t->data;
3406
mode = (G.editBMesh->options & BME_BEVEL_VERT) ? "verts only" : "normal";
3407
distance = InputHorizontalAbsolute(t, mval)/4; /* 4 just seemed a nice value to me, nothing special */
3409
applyNumInput(&t->num, &distance);
3411
/* header print for NumInput */
3412
if (hasNumInput(&t->num)) {
3415
outputNumInput(&(t->num), c);
3417
sprintf(str, "Bevel: %s", c);
3420
/* default header print */
3421
sprintf(str, "Bevel - Dist: %.4f, Mode: %s (MMB to toggle))", distance, mode);
3424
if (distance < 0) distance = -distance;
3425
for(i = 0 ; i < t->total; i++, td++) {
3426
if (td->axismtx[1][0] > 0 && distance > td->axismtx[1][0]) {
3427
d = td->axismtx[1][0];
3432
VECADDFAC(td->loc,td->center,td->axismtx[0],(*td->val)*d);
3444
/* ************************** BEVEL WEIGHT *************************** */
3446
void initBevelWeight(TransInfo *t)
3448
t->mode = TFM_BWEIGHT;
3449
t->transform = BevelWeight;
3455
t->snap[2] = t->snap[1] * 0.1f;
3457
t->flag |= T_NO_CONSTRAINT;
3459
t->fac = (float)sqrt(
3461
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
3463
((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
3466
if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
3469
int BevelWeight(TransInfo *t, short mval[2])
3471
TransData *td = t->data;
3477
if(t->flag & T_SHIFT_MOD) {
3478
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
3479
float dx= (float)(t->center2d[0] - t->shiftmval[0]);
3480
float dy= (float)(t->center2d[1] - t->shiftmval[1]);
3481
weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
3483
dx= (float)(t->center2d[0] - mval[0]);
3484
dy= (float)(t->center2d[1] - mval[1]);
3485
weight+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -weight);
3489
float dx= (float)(t->center2d[0] - mval[0]);
3490
float dy= (float)(t->center2d[1] - mval[1]);
3491
weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
3495
if (weight > 1.0f) weight = 1.0f;
3497
snapGrid(t, &weight);
3499
applyNumInput(&t->num, &weight);
3501
/* header print for NumInput */
3502
if (hasNumInput(&t->num)) {
3505
outputNumInput(&(t->num), c);
3508
sprintf(str, "Bevel Weight: +%s %s", c, t->proptext);
3510
sprintf(str, "Bevel Weight: %s %s", c, t->proptext);
3513
/* default header print */
3515
sprintf(str, "Bevel Weight: +%.3f %s", weight, t->proptext);
3517
sprintf(str, "Bevel Weight: %.3f %s", weight, t->proptext);
3520
for(i = 0 ; i < t->total; i++, td++) {
3521
if (td->flag & TD_NOACTION)
3525
*td->val = td->ival + weight * td->factor;
3526
if (*td->val < 0.0f) *td->val = 0.0f;
3527
if (*td->val > 1.0f) *td->val = 1.0f;
3537
helpline (t, t->center);
2408
3542
/* ************************** CREASE *************************** */
2410
3544
void initCrease(TransInfo *t)
2416
t->snap[2] = t->snap[1] * 0.1f;
3546
t->mode = TFM_CREASE;
2417
3547
t->transform = Crease;
3553
t->snap[2] = t->snap[1] * 0.1f;
3555
t->flag |= T_NO_CONSTRAINT;
2418
3557
t->fac = (float)sqrt(
2420
3559
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2501
/* ************************** MIRROR *************************** */
2503
void Mirror(short mode)
2506
float mati[3][3], matview[3][3], mat[3][3];
2510
Trans.context = CTX_NO_PET;
2512
initTrans(&Trans); // internal data, mouse, vectors
2515
Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
2518
initTransModeFlags(&Trans, TFM_MIRROR); // modal settings in struct Trans
2520
createTransData(&Trans); // make TransData structs from selection
2522
calculatePropRatio(&Trans);
2523
calculateCenter(&Trans);
2527
if (Trans.total == 0) {
2532
size[0] = size[1] = size[2] = 1.0f;
2538
setConstraint(&Trans, mati, (CON_AXIS0), "");
2542
setConstraint(&Trans, mati, (CON_AXIS1), "");
2546
setConstraint(&Trans, mati, (CON_AXIS2), "");
2550
setLocalConstraint(&Trans, (CON_AXIS0), "");
2554
setLocalConstraint(&Trans, (CON_AXIS1), "");
2558
setLocalConstraint(&Trans, (CON_AXIS2), "");
2562
setConstraint(&Trans, matview, (CON_AXIS0), "");
2566
setConstraint(&Trans, matview, (CON_AXIS1), "");
2570
setConstraint(&Trans, matview, (CON_AXIS2), "");
2576
SizeToMat3(size, mat);
2578
if (Trans.con.applySize) {
2579
Trans.con.applySize(&Trans, NULL, mat);
2582
for(i = 0 ; i < Trans.total; i++, td++) {
2583
if (td->flag & TD_NOACTION)
2586
ElementResize(&Trans, td, mat);
2591
BIF_undo_push("Mirror");
2593
/* free data, reset vars */
2596
/* send events out for redraws */
2597
viewRedrawPost(&Trans);
2600
3643
/* ******************** EditBone (B-bone) width scaling *************** */
3645
void initBoneSize(TransInfo *t)
3647
t->mode = TFM_BONESIZE;
3648
t->transform = BoneSize;
3652
t->num.flag |= NUM_NULL_ONE;
3655
t->snap[2] = t->snap[1] * 0.1f;
3657
t->fac = (float)sqrt( (
3658
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
3660
((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
3663
if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
3666
static void headerBoneSize(TransInfo *t, float vec[3], char *str) {
3668
if (hasNumInput(&t->num)) {
3669
outputNumInput(&(t->num), tvec);
3672
sprintf(&tvec[0], "%.4f", vec[0]);
3673
sprintf(&tvec[20], "%.4f", vec[1]);
3674
sprintf(&tvec[40], "%.4f", vec[2]);
3677
/* hmm... perhaps the y-axis values don't need to be shown? */
3678
if (t->con.mode & CON_APPLY) {
3679
if (t->num.idx_max == 0)
3680
sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext);
3682
sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
3685
sprintf(str, "ScaleB X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2602
3689
static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
2604
3691
float tmat[3][3], smat[3][3], oldy;
2787
3808
if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
3811
int BoneEnvelope(TransInfo *t, short mval[2])
3813
TransData *td = t->data;
3818
if(t->flag & T_SHIFT_MOD) {
3819
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
3820
float dx= (float)(t->center2d[0] - t->shiftmval[0]);
3821
float dy= (float)(t->center2d[1] - t->shiftmval[1]);
3822
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
3824
dx= (float)(t->center2d[0] - mval[0]);
3825
dy= (float)(t->center2d[1] - mval[1]);
3826
ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
3830
float dx= (float)(t->center2d[0] - mval[0]);
3831
float dy= (float)(t->center2d[1] - mval[1]);
3832
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
3835
snapGrid(t, &ratio);
3837
applyNumInput(&t->num, &ratio);
3839
/* header print for NumInput */
3840
if (hasNumInput(&t->num)) {
3843
outputNumInput(&(t->num), c);
3844
sprintf(str, "Envelope: %s", c);
3847
sprintf(str, "Envelope: %3f", ratio);
3850
for(i = 0 ; i < t->total; i++, td++) {
3851
if (td->flag & TD_NOACTION)
3854
if (td->flag & TD_SKIP)
3858
/* if the old/original value was 0.0f, then just use ratio */
3860
*td->val= td->ival*ratio;
3872
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
3878
/* ******************** EditBone roll *************** */
3880
void initBoneRoll(TransInfo *t)
3882
t->mode = TFM_BONE_ROLL;
3883
t->transform = BoneRoll;
3888
t->snap[1] = (float)((5.0/180)*M_PI);
3889
t->snap[2] = t->snap[1] * 0.2f;
3893
t->flag |= T_NO_CONSTRAINT;
3896
int BoneRoll(TransInfo *t, short mval[2])
3898
TransData *td = t->data;
3904
t->fac += InputDeltaAngle(t, mval);
3908
snapGrid(t, &final);
3910
if (hasNumInput(&t->num)) {
3913
applyNumInput(&t->num, &final);
3915
outputNumInput(&(t->num), c);
3917
sprintf(str, "Roll: %s", &c[0]);
3919
final *= (float)(M_PI / 180.0);
3922
sprintf(str, "Roll: %.2f", 180.0*final/M_PI);
3925
/* set roll values */
3926
for (i = 0; i < t->total; i++, td++) {
3927
if (td->flag & TD_NOACTION)
3930
if (td->flag & TD_SKIP)
3933
*(td->val) = td->ival - final;
3942
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
3947
/* ************************** BAKE TIME ******************* */
3949
void initBakeTime(TransInfo *t)
3955
t->snap[2] = t->snap[1] * 0.1f;
3956
t->transform = BakeTime;
3960
int BakeTime(TransInfo *t, short mval[2])
3962
TransData *td = t->data;
3968
if(t->flag & T_SHIFT_MOD) {
3969
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
3970
time= (float)(t->center2d[0] - t->shiftmval[0])*t->fac;
3971
time+= 0.1f*((float)(t->center2d[0]*t->fac - mval[0]) -time);
3974
time = (float)(t->center2d[0] - mval[0])*t->fac;
3979
applyNumInput(&t->num, &time);
3981
/* header print for NumInput */
3982
if (hasNumInput(&t->num)) {
3985
outputNumInput(&(t->num), c);
3988
sprintf(str, "Time: +%s %s", c, t->proptext);
3990
sprintf(str, "Time: %s %s", c, t->proptext);
3993
/* default header print */
3995
sprintf(str, "Time: +%.3f %s", time, t->proptext);
3997
sprintf(str, "Time: %.3f %s", time, t->proptext);
4000
for(i = 0 ; i < t->total; i++, td++) {
4001
if (td->flag & TD_NOACTION)
4004
if (td->flag & TD_SKIP)
4008
*td->val = td->ival + time * td->factor;
4009
if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
4010
if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
4020
helpline (t, t->center);
4025
/* ************************** MIRROR *************************** */
4027
void initMirror(TransInfo *t)
4029
t->flag |= T_NULL_ONE;
4031
t->flag |= T_NO_ZERO;
4034
t->transform = Mirror;
4037
int Mirror(TransInfo *t, short mval[2])
4040
float size[3], mat[3][3];
4046
* This still recalcs transformation on mouse move
4047
* while it should only recalc on constraint change
4050
/* if an axis has been selected */
4051
if (t->con.mode & CON_APPLY) {
4052
size[0] = size[1] = size[2] = -1;
4054
SizeToMat3(size, mat);
4056
if (t->con.applySize) {
4057
t->con.applySize(t, NULL, mat);
4060
sprintf(str, "Mirror%s", t->con.text);
4062
for(i = 0, td=t->data; i < t->total; i++, td++) {
4063
if (td->flag & TD_NOACTION)
4066
if (td->flag & TD_SKIP)
4069
ElementResize(t, td, mat);
4080
size[0] = size[1] = size[2] = 1;
4082
SizeToMat3(size, mat);
4084
for(i = 0, td=t->data; i < t->total; i++, td++) {
4085
if (td->flag & TD_NOACTION)
4088
if (td->flag & TD_SKIP)
4091
ElementResize(t, td, mat);
4096
headerprint("Select a mirror axis (X, Y, Z)");
4104
/* ************************** ALIGN *************************** */
4106
void initAlign(TransInfo *t)
4108
t->flag |= T_NO_CONSTRAINT;
4110
t->transform = Align;
4113
int Align(TransInfo *t, short mval[2])
4115
TransData *td = t->data;
4119
/* saving original center */
4120
VECCOPY(center, t->center);
4122
for(i = 0 ; i < t->total; i++, td++)
4124
float mat[3][3], invmat[3][3];
4126
if (td->flag & TD_NOACTION)
4129
if (td->flag & TD_SKIP)
4132
/* around local centers */
4133
if (t->flag & (T_OBJECT|T_POSE)) {
4134
VECCOPY(t->center, td->center);
4137
if(G.scene->selectmode & SCE_SELECT_FACE) {
4138
VECCOPY(t->center, td->center);
4142
Mat3Inv(invmat, td->axismtx);
4144
Mat3MulMat3(mat, t->spacemtx, invmat);
4146
ElementRotation(t, td, mat);
4149
/* restoring original center */
4150
VECCOPY(t->center, center);
4154
headerprint("Align");
4159
/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */
4161
/* ---------------- Special Helpers for Various Settings ------------- */
4163
/* This function returns the snapping 'mode' for Animation Editors only
4164
* We cannot use the standard snapping due to NLA-strip scaling complexities.
4166
static short getAnimEdit_SnapMode(TransInfo *t)
4168
short autosnap= SACTSNAP_OFF;
4170
/* currently, some of these are only for the action editor */
4171
if (t->spacetype == SPACE_ACTION && G.saction) {
4172
switch (G.saction->autosnap) {
4174
if (G.qual == LR_CTRLKEY)
4175
autosnap= SACTSNAP_STEP;
4176
else if (G.qual == LR_SHIFTKEY)
4177
autosnap= SACTSNAP_FRAME;
4178
else if (G.qual == LR_ALTKEY)
4179
autosnap= SACTSNAP_MARKER;
4181
autosnap= SACTSNAP_OFF;
4184
autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
4186
case SACTSNAP_FRAME:
4187
autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
4189
case SACTSNAP_MARKER:
4190
autosnap= (G.qual==LR_ALTKEY)? SACTSNAP_OFF: SACTSNAP_MARKER;
4194
else if (t->spacetype == SPACE_NLA && G.snla) {
4195
switch (G.snla->autosnap) {
4197
if (G.qual == LR_CTRLKEY)
4198
autosnap= SACTSNAP_STEP;
4199
else if (G.qual == LR_SHIFTKEY)
4200
autosnap= SACTSNAP_FRAME;
4201
else if (G.qual == LR_ALTKEY)
4202
autosnap= SACTSNAP_MARKER;
4204
autosnap= SACTSNAP_OFF;
4207
autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
4209
case SACTSNAP_FRAME:
4210
autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
4212
case SACTSNAP_MARKER:
4213
autosnap= (G.qual==LR_ALTKEY)? SACTSNAP_OFF: SACTSNAP_MARKER;
4218
if (G.qual == LR_CTRLKEY)
4219
autosnap= SACTSNAP_STEP;
4220
else if (G.qual == LR_SHIFTKEY)
4221
autosnap= SACTSNAP_FRAME;
4222
else if (G.qual == LR_ALTKEY)
4223
autosnap= SACTSNAP_MARKER;
4225
autosnap= SACTSNAP_OFF;
4231
/* This function is used for testing if an Animation Editor is displaying
4232
* its data in frames or seconds (and the data needing to be edited as such).
4233
* Returns 1 if in seconds, 0 if in frames
4235
static short getAnimEdit_DrawTime(TransInfo *t)
4239
/* currently, some of these are only for the action editor */
4240
if (t->spacetype == SPACE_ACTION && G.saction) {
4241
drawtime = (G.saction->flag & SACTION_DRAWTIME)? 1 : 0;
4243
else if (t->spacetype == SPACE_NLA && G.snla) {
4244
drawtime = (G.snla->flag & SNLA_DRAWTIME)? 1 : 0;
4254
/* This function is used by Animation Editor specific transform functions to do
4255
* the Snap Keyframe to Nearest Frame/Marker
4257
static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap)
4259
/* snap key to nearest frame? */
4260
if (autosnap == SACTSNAP_FRAME) {
4261
short doTime= getAnimEdit_DrawTime(t);
4265
/* convert frame to nla-action time (if needed) */
4267
val= get_action_frame_inv(ob, *(td->val));
4271
/* do the snapping to nearest frame/second */
4273
val= (float)( floor((val/secf) + 0.5f) * secf );
4275
val= (float)( floor(val+0.5f) );
4277
/* convert frame out of nla-action time */
4279
*(td->val)= get_action_frame(ob, val);
4283
/* snap key to nearest marker? */
4284
else if (autosnap == SACTSNAP_MARKER) {
4287
/* convert frame to nla-action time (if needed) */
4289
val= get_action_frame_inv(ob, *(td->val));
4293
/* snap to nearest marker */
4294
val= (float)find_nearest_marker_time(val);
4296
/* convert frame out of nla-action time */
4298
*(td->val)= get_action_frame(ob, val);
4304
/* ----------------- Translation ----------------------- */
4306
void initTimeTranslate(TransInfo *t)
4308
t->mode = TFM_TIME_TRANSLATE;
4309
t->transform = TimeTranslate;
4311
/* num-input has max of (n-1) */
4314
t->num.idx_max = t->idx_max;
4316
/* initialise snap like for everything else */
4318
t->snap[1] = t->snap[2] = 1.0f;
4321
static void headerTimeTranslate(TransInfo *t, char *str)
4325
/* if numeric input is active, use results from that, otherwise apply snapping to result */
4326
if (hasNumInput(&t->num)) {
4327
outputNumInput(&(t->num), tvec);
4330
short autosnap= getAnimEdit_SnapMode(t);
4331
short doTime = getAnimEdit_DrawTime(t);
4335
/* apply snapping + frame->seconds conversions */
4336
if (autosnap == SACTSNAP_STEP) {
4338
val= floor(val/secf + 0.5f);
4340
val= floor(val + 0.5f);
4347
sprintf(&tvec[0], "%.4f", val);
4350
sprintf(str, "DeltaX: %s", &tvec[0]);
4353
static void applyTimeTranslate(TransInfo *t, float sval)
4355
TransData *td = t->data;
4358
short doTime= getAnimEdit_DrawTime(t);
4361
short autosnap= getAnimEdit_SnapMode(t);
4365
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
4366
for (i = 0 ; i < t->total; i++, td++) {
4367
/* it is assumed that td->ob is a pointer to the object,
4368
* whose active action is where this keyframe comes from
4372
/* check if any need to apply nla-scaling */
4376
if (autosnap == SACTSNAP_STEP) {
4378
deltax= (float)( floor((deltax/secf) + 0.5f) * secf );
4380
deltax= (float)( floor(deltax + 0.5f) );
4383
val = get_action_frame_inv(ob, td->ival);
4385
*(td->val) = get_action_frame(ob, val);
4388
deltax = val = t->fac;
4390
if (autosnap == SACTSNAP_STEP) {
4392
val= (float)( floor((deltax/secf) + 0.5f) * secf );
4394
val= (float)( floor(val + 0.5f) );
4397
*(td->val) = td->ival + val;
4400
/* apply nearest snapping */
4401
doAnimEdit_SnapFrame(t, td, ob, autosnap);
4405
int TimeTranslate(TransInfo *t, short mval[2])
4407
float cval[2], sval[2];
4410
/* calculate translation amount from mouse movement - in 'time-grid space' */
4411
areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]);
4412
areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
4414
/* we only need to calculate effect for time (applyTimeTranslate only needs that) */
4415
t->fac= cval[0] - sval[0];
4417
/* handle numeric-input stuff */
4419
applyNumInput(&t->num, &t->vec[0]);
4421
headerTimeTranslate(t, str);
4423
applyTimeTranslate(t, sval[0]);
4434
/* ----------------- Time Slide ----------------------- */
4436
void initTimeSlide(TransInfo *t)
4438
/* this tool is only really available in the Action Editor... */
4439
if (t->spacetype == SPACE_ACTION) {
4440
/* set flag for drawing stuff*/
4441
G.saction->flag |= SACTION_MOVING;
4444
t->mode = TFM_TIME_SLIDE;
4445
t->transform = TimeSlide;
4446
t->flag |= T_FREE_CUSTOMDATA;
4448
/* num-input has max of (n-1) */
4451
t->num.idx_max = t->idx_max;
4453
/* initialise snap like for everything else */
4455
t->snap[1] = t->snap[2] = 1.0f;
4458
static void headerTimeSlide(TransInfo *t, float sval, char *str)
4462
if (hasNumInput(&t->num)) {
4463
outputNumInput(&(t->num), tvec);
4466
float minx= *((float *)(t->customData));
4467
float maxx= *((float *)(t->customData) + 1);
4471
val= 2.0*(cval-sval) / (maxx-minx);
4472
CLAMP(val, -1.0f, 1.0f);
4474
sprintf(&tvec[0], "%.4f", val);
4477
sprintf(str, "TimeSlide: %s", &tvec[0]);
4480
static void applyTimeSlide(TransInfo *t, float sval)
4482
TransData *td = t->data;
4485
float minx= *((float *)(t->customData));
4486
float maxx= *((float *)(t->customData) + 1);
4489
/* set value for drawing black line */
4490
if (t->spacetype == SPACE_ACTION) {
4491
float cvalf = t->fac;
4493
if (NLA_ACTION_SCALED)
4494
cvalf= get_action_frame(OBACT, cvalf);
4496
G.saction->timeslide= cvalf;
4499
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
4500
for (i = 0 ; i < t->total; i++, td++) {
4501
/* it is assumed that td->ob is a pointer to the object,
4502
* whose active action is where this keyframe comes from
4505
float cval = t->fac;
4507
/* apply scaling to necessary values */
4509
cval= get_action_frame(ob, cval);
4511
/* only apply to data if in range */
4512
if ((sval > minx) && (sval < maxx)) {
4513
float cvalc= CLAMPIS(cval, minx, maxx);
4517
if (td->ival < sval) {
4518
timefac= (sval - td->ival) / (sval - minx);
4519
*(td->val)= cvalc - timefac * (cvalc - minx);
4522
timefac= (td->ival - sval) / (maxx - sval);
4523
*(td->val)= cvalc + timefac * (maxx - cvalc);
4529
int TimeSlide(TransInfo *t, short mval[2])
4531
float cval[2], sval[2];
4532
float minx= *((float *)(t->customData));
4533
float maxx= *((float *)(t->customData) + 1);
4536
/* calculate mouse co-ordinates */
4537
areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]);
4538
areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
4540
/* t->fac stores cval[0], which is the current mouse-pointer location (in frames) */
4543
/* handle numeric-input stuff */
4544
t->vec[0] = 2.0*(cval[0]-sval[0]) / (maxx-minx);
4545
applyNumInput(&t->num, &t->vec[0]);
4546
t->fac = (maxx-minx) * t->vec[0] / 2.0 + sval[0];
4548
headerTimeSlide(t, sval[0], str);
4549
applyTimeSlide(t, sval[0]);
4560
/* ----------------- Scaling ----------------------- */
4562
void initTimeScale(TransInfo *t)
4564
t->mode = TFM_TIME_SCALE;
4565
t->transform = TimeScale;
4567
t->flag |= T_NULL_ONE;
4568
t->num.flag |= NUM_NULL_ONE;
4570
/* num-input has max of (n-1) */
4573
t->num.idx_max = t->idx_max;
4575
/* initialise snap like for everything else */
4577
t->snap[1] = t->snap[2] = 1.0f;
4580
static void headerTimeScale(TransInfo *t, char *str) {
4583
if (hasNumInput(&t->num))
4584
outputNumInput(&(t->num), tvec);
4586
sprintf(&tvec[0], "%.4f", t->fac);
4588
sprintf(str, "ScaleX: %s", &tvec[0]);
4591
static void applyTimeScale(TransInfo *t) {
4592
TransData *td = t->data;
4595
short autosnap= getAnimEdit_SnapMode(t);
4596
short doTime= getAnimEdit_DrawTime(t);
4600
for (i = 0 ; i < t->total; i++, td++) {
4601
/* it is assumed that td->ob is a pointer to the object,
4602
* whose active action is where this keyframe comes from
4608
if (autosnap == SACTSNAP_STEP) {
4610
fac= (float)( floor(fac/secf + 0.5f) * secf );
4612
fac= (float)( floor(fac + 0.5f) );
4615
/* check if any need to apply nla-scaling */
4617
startx= get_action_frame(ob, startx);
4619
/* now, calculate the new value */
4620
*(td->val) = td->ival - startx;
4622
*(td->val) += startx;
4624
/* apply nearest snapping */
4625
doAnimEdit_SnapFrame(t, td, ob, autosnap);
4629
int TimeScale(TransInfo *t, short mval[2])
4632
float deltax, startx;
4639
switch (t->spacetype) {
4648
/* calculate scaling factor */
4649
startx= sval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
4650
deltax= cval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
4651
t->fac = deltax / startx;
4653
/* handle numeric-input stuff */
4655
applyNumInput(&t->num, &t->vec[0]);
4657
headerTimeScale(t, str);
2790
4670
/* ************************************ */
2792
4672
void BIF_TransformSetUndo(char *str)