=== Mirror Tool ===

Making the mirror tool axis selection interactive instead of using a popmenu.

Mirror is now just a constant -1 scaling transform, which enables you to choose the mirror axis through hotkeys (x,y,z) and with MMB. It also means it's easier to select the correct axis if you're not sure which is which and gives access to all the orientation supported in transform (including custom user orientations).

Mesh and Object header menus still have the individual axis as options but have an added "Interactive Mirror" which just enters transform and lets user pick the axis there. Ctrl-M enters "Interactive Mirror" too.

In a nutshell, this changes adds more possible mirroring axis and unifies the mirror axis selection process with transform constraint axis selection.
This commit is contained in:
Martin Poirier 2008-01-24 20:11:54 +00:00
parent 9c02ca37d6
commit 450b3664e1
5 changed files with 147 additions and 120 deletions

@ -68,10 +68,10 @@
#define CTX_NO_PET 4 #define CTX_NO_PET 4
#define CTX_TWEAK 8 #define CTX_TWEAK 8
#define CTX_NO_MIRROR 16 #define CTX_NO_MIRROR 16
#define CTX_AUTOCONFIRM 32
void initTransform(int mode, int context); void initTransform(int mode, int context);
void Transform(void); void Transform(void);
void Mirror(short mode);
/* Standalone call to get the transformation center corresponding to the current situation /* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection) * returns 1 if successful, 0 otherwise (usually means there's no selection)

@ -363,6 +363,9 @@ int TimeScale(TransInfo *t, short mval[2]);
void initBakeTime(TransInfo *t); void initBakeTime(TransInfo *t);
int BakeTime(TransInfo *t, short mval[2]); int BakeTime(TransInfo *t, short mval[2]);
void initMirror(TransInfo *t);
int Mirror(TransInfo *t, short mval[2]);
/*********************** transform_conversions.c ********** */ /*********************** transform_conversions.c ********** */
struct ListBase; struct ListBase;
void flushTransIpoData(TransInfo *t); void flushTransIpoData(TransInfo *t);

@ -5574,17 +5574,9 @@ void mirrormenu(void)
if(G.f & G_PARTICLEEDIT) { if(G.f & G_PARTICLEEDIT) {
PE_mirror_x(0); PE_mirror_x(0);
} }
else if (G.obedit==0) {
mode=pupmenu("Mirror Axis %t|X Local%x4|Y Local%x5|Z Local%x6|");
if (mode==-1) return; /* return */
Mirror(mode); /* separating functionality from interface | call*/
}
else { else {
mode=pupmenu("Mirror Axis %t|X Global%x1|Y Global%x2|Z Global%x3|%l|X Local%x4|Y Local%x5|Z Local%x6|%l|X View%x7|Y View%x8|Z View%x9|"); initTransform(TFM_MIRROR, CTX_NO_PET);
Transform();
if (mode==-1) return; /* return */
Mirror(mode); /* separating functionality from interface | call*/
} }
} }

@ -1881,10 +1881,24 @@ static uiBlock *view3d_transformmenu(void *arg_unused)
void do_view3d_object_mirrormenu(void *arg, int event) void do_view3d_object_mirrormenu(void *arg, int event)
{ {
switch(event) { switch(event) {
case 0:
initTransform(TFM_MIRROR, CTX_NO_PET);
Transform();
break;
case 1: case 1:
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setLocalAxisConstraint('X', " on X axis");
Transform();
break;
case 2: case 2:
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setLocalAxisConstraint('Y', " on Y axis");
Transform();
break;
case 3: case 3:
Mirror(event + 3); /* + 3 because the first three modes are global*/ initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setLocalAxisConstraint('Z', " on Z axis");
Transform();
break; break;
} }
allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWVIEW3D, 0);
@ -1898,9 +1912,11 @@ static uiBlock *view3d_object_mirrormenu(void *arg_unused)
block= uiNewBlock(&curarea->uiblocks, "view3d_object_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); block= uiNewBlock(&curarea->uiblocks, "view3d_object_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
uiBlockSetButmFunc(block, do_view3d_object_mirrormenu, NULL); uiBlockSetButmFunc(block, do_view3d_object_mirrormenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|Ctrl M, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Interactive Mirror|Ctrl M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|Ctrl M, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|Ctrl M, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|Ctrl M, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|Ctrl M, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|Ctrl M, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiBlockSetDirection(block, UI_RIGHT); uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 60); uiTextBoundsBlock(block, 60);
@ -2853,17 +2869,44 @@ static uiBlock *view3d_edit_mesh_normalsmenu(void *arg_unused)
void do_view3d_edit_mirrormenu(void *arg, int event) void do_view3d_edit_mirrormenu(void *arg, int event)
{ {
float mat[3][3];
Mat3One(mat);
switch(event) { switch(event) {
case 0:
initTransform(TFM_MIRROR, CTX_NO_PET);
Transform();
break;
case 1: case 1:
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setSingleAxisConstraint(mat[0], " on global X axis");
Transform();
break;
case 2: case 2:
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setSingleAxisConstraint(mat[1], " on global Y axis");
Transform();
break;
case 3: case 3:
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setSingleAxisConstraint(mat[2], "on global Z axis");
Transform();
break;
case 4: case 4:
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setLocalAxisConstraint('X', " on local X axis");
Transform();
break;
case 5: case 5:
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
BIF_setLocalAxisConstraint('Y', " on local Y axis");
Transform();
break;
case 6: case 6:
case 7: initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
case 8: BIF_setLocalAxisConstraint('Z', " on local Z axis");
case 9: Transform();
Mirror(event);
break; break;
} }
allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWVIEW3D, 0);
@ -2877,21 +2920,19 @@ static uiBlock *view3d_edit_mirrormenu(void *arg_unused)
block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
uiBlockSetButmFunc(block, do_view3d_edit_mirrormenu, NULL); uiBlockSetButmFunc(block, do_view3d_edit_mirrormenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Global|Ctrl M, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Interactive Mirror|Ctrl M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Global|Ctrl M, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Global|Ctrl M, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|Ctrl M, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Global|Ctrl M, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|Ctrl M, 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Global|Ctrl M, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|Ctrl M, 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Global|Ctrl M, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X View|Ctrl M, 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|Ctrl M, X X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y View|Ctrl M, 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|Ctrl M, Y Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z View|Ctrl M, 9", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|Ctrl M, Z Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
uiBlockSetDirection(block, UI_RIGHT); uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 60); uiTextBoundsBlock(block, 60);

@ -888,6 +888,8 @@ static char *transform_to_undostr(TransInfo *t)
return "Time Slide"; return "Time Slide";
case TFM_BAKE_TIME: case TFM_BAKE_TIME:
return "Key Time"; return "Key Time";
case TFM_MIRROR:
return "Mirror";
} }
return "Transform"; return "Transform";
} }
@ -1323,6 +1325,9 @@ void initTransform(int mode, int context) {
case TFM_BAKE_TIME: case TFM_BAKE_TIME:
initBakeTime(&Trans); initBakeTime(&Trans);
break; break;
case TFM_MIRROR:
initMirror(&Trans);
break;
} }
} }
@ -1360,6 +1365,13 @@ void Transform()
Trans.redraw = 0; Trans.redraw = 0;
} }
/* If auto confirm is on, break after one pass */
if (Trans.context & CTX_AUTOCONFIRM)
{
Trans.state = TRANS_CONFIRM;
break;
}
/* essential for idling subloop */ /* essential for idling subloop */
if( qtest()==0) PIL_sleep_ms(2); if( qtest()==0) PIL_sleep_ms(2);
@ -4033,105 +4045,84 @@ int BakeTime(TransInfo *t, short mval[2])
return 1; return 1;
} }
/* ************************** MIRROR *************************** */ /* ************************** MIRROR *************************** */
void Mirror(short mode) void initMirror(TransInfo *t)
{
t->flag |= T_NULL_ONE;
if (!G.obedit) {
t->flag |= T_NO_ZERO;
}
t->transform = Mirror;
t->fac = 0.1f;
}
int Mirror(TransInfo *t, short mval[2])
{ {
TransData *td; TransData *td;
float mati[3][3], matview[3][3], mat[3][3]; float size[3], mat[3][3];
float size[3];
int i; int i;
char str[200];
Trans.context = CTX_NO_PET; /*
* OPTIMISATION:
* This still recalcs transformation on mouse move
* while it should only recalc on constraint change
* */
initTrans(&Trans); // internal data, mouse, vectors /* if an axis has been selected */
if (t->con.mode & CON_APPLY) {
if (t->con.applySize) {
t->con.applySize(t, NULL, mat);
}
Mat3One(mati); sprintf(str, "Mirror%s", t->con.text);
Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
Mat3Ortho(matview);
createTransData(&Trans); // make TransData structs from selection size[0] = size[1] = size[2] = -1;
calculatePropRatio(&Trans); SizeToMat3(size, mat);
calculateCenter(&Trans);
initResize(&Trans); for(i = 0, td=t->data; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (Trans.total == 0) { if (td->flag & TD_SKIP)
postTrans(&Trans); continue;
return;
ElementResize(t, td, mat);
}
recalcData(t);
headerprint(str);
viewRedrawForce(t);
}
else
{
size[0] = size[1] = size[2] = 1;
SizeToMat3(size, mat);
for(i = 0, td=t->data; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
ElementResize(t, td, mat);
}
recalcData(t);
headerprint("Select a mirror axis (X, Y, Z)");
viewRedrawForce(t);
} }
size[0] = size[1] = size[2] = 1.0f; return 1;
td = Trans.data;
switch (mode) {
case 1:
size[0] = -1.0f;
setConstraint(&Trans, mati, (CON_AXIS0), "");
break;
case 2:
size[1] = -1.0f;
setConstraint(&Trans, mati, (CON_AXIS1), "");
break;
case 3:
size[2] = -1.0f;
setConstraint(&Trans, mati, (CON_AXIS2), "");
break;
case 4:
size[0] = -1.0f;
setLocalConstraint(&Trans, (CON_AXIS0), "");
break;
case 5:
size[1] = -1.0f;
setLocalConstraint(&Trans, (CON_AXIS1), "");
break;
case 6:
size[2] = -1.0f;
setLocalConstraint(&Trans, (CON_AXIS2), "");
break;
case 7:
size[0] = -1.0f;
setConstraint(&Trans, matview, (CON_AXIS0), "");
break;
case 8:
size[1] = -1.0f;
setConstraint(&Trans, matview, (CON_AXIS1), "");
break;
case 9:
size[2] = -1.0f;
setConstraint(&Trans, matview, (CON_AXIS2), "");
break;
default:
return;
}
SizeToMat3(size, mat);
if (Trans.con.applySize) {
Trans.con.applySize(&Trans, NULL, mat);
}
for(i = 0 ; i < Trans.total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
ElementResize(&Trans, td, mat);
}
recalcData(&Trans);
BIF_undo_push("Mirror");
/* free data, reset vars */
postTrans(&Trans);
/* send events out for redraws */
viewRedrawPost(&Trans);
} }
/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */ /* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */