Transform widgets; Scale and Rotate versions

To use; press the (temporal) icon in header. Switching widget types is by
pressing G, R or S once, if current widget type is different it switches,
otherwise it goes to normal Transform().

Widgets need a bit test for picking accuracy, correct drawing etc.
The rotate widget has a center button for 'trackball' rotate. That latter
can also be used for hotkey-based rotate.

In current code, all widgets remain in "Global" space, also in editmode.
Also widget updates while using normal transform has to be done.

2 Bugfixes:
- rotate in PoseMode had error for 2d 'around' center
- transform in postemode could crash, due to typo (& or |)
This commit is contained in:
Ton Roosendaal 2005-03-19 12:17:06 +00:00
parent a96ed881dc
commit a2ed880c9f
12 changed files with 621 additions and 73 deletions

@ -4625,6 +4625,7 @@ static void do_versions(Main *main)
if(main->versionfile <= 236) {
Scene *sce= main->scene.first;
Camera *cam= main->camera.first;
bScreen *sc;
while(sce) {
if(sce->r.postsat==0.0) sce->r.postsat= 1.0;
@ -4637,6 +4638,19 @@ static void do_versions(Main *main)
}
cam= cam->id.next;
}
/* set manipulator type */
for (sc= main->screen.first; sc; sc= sc->id.next) {
ScrArea *sa;
for (sa= sc->areabase.first; sa; sa= sa->next) {
SpaceLink *sl;
for (sl= sa->spacedata.first; sl; sl= sl->next) {
if(sl->spacetype==SPACE_VIEW3D) {
View3D *v3d= (View3D *)sl;
if(v3d->twtype==0) v3d->twtype= V3D_MANIPULATOR_TRANSLATE;
}
}
}
}
}
/* don't forget to set version number in blender.c! */

@ -61,6 +61,7 @@ void drawcircball(float *cent, float rad, float tmat[][4]);
void get_local_bounds(struct Object *ob, float *centre, float *size);
void draw_object(struct Base *base);
void draw_object_ext(struct Base *base);
void drawsolidcube(float size);
extern void draw_object_backbufsel(struct Object *ob);
#ifdef __cplusplus

@ -33,7 +33,7 @@
#ifndef BIF_TRANSFORM_H
#define BIF_TRANSFORM_H
#define NEWTRANSFORM 1
//#define NEWTRANSFORM 1
/* ******************** Macros & Prototypes *********************** */
@ -49,6 +49,7 @@
#define TFM_TILT 9
#define TFM_LAMP_ENERGY 10
#define TFM_TRACKBALL 11
// not sure if adding modes is the right way... context detecting could be done different (ton)
#define TFM_TEX 32

@ -147,10 +147,10 @@ typedef struct View3D {
#define V3D_SHOW_Y 4
#define V3D_SHOW_Z 8
/* View3d->twtype */
#define V3D_MANIPULATOR_TRANSLATE 0
#define V3D_MANIPULATOR_ROTATE 1
#define V3D_MANIPULATOR_SCALE 2
/* View3d->twtype (bits, we can combine them) */
#define V3D_MANIPULATOR_TRANSLATE 1
#define V3D_MANIPULATOR_ROTATE 2
#define V3D_MANIPULATOR_SCALE 4
/* View3d->twmode */
#define V3D_MANIPULATOR_GLOBAL 0

@ -318,11 +318,14 @@ void drawaxes(float size)
}
}
#if 0
static void drawgourcube(void)
void drawsolidcube(float size)
{
float n[3];
glPushMatrix();
glScalef(size, size, size);
n[0]=0; n[1]=0; n[2]=0;
glBegin(GL_QUADS);
n[0]= -1.0;
@ -364,8 +367,9 @@ static void drawgourcube(void)
glNormal3fv(n);
glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
glEnd();
glPopMatrix();
}
#endif
static void drawcube(void)
{

@ -1217,7 +1217,12 @@ void screenmain(void)
if (event==0 || event==EXECUTE) {
screen_dispatch_events();
}
if(G.f & G_DEBUG) {
GLenum error = glGetError();
if (error)
printf("GL error: %s\n", gluErrorString(error));
}
/* Bizar hack. The event queue has mutated... */
if ( (firsttime) && (event == 0) ) {

@ -720,7 +720,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
unsigned short event= evt->event;
short val= evt->val;
char ascii= evt->ascii;
View3D *v3d= curarea->spacedata.first;
View3D *v3d= sa->spacedata.first;
Object *ob;
float *curs;
int doredraw= 0, pupval;
@ -1220,12 +1220,20 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if(okee("Clear location")) {
clear_object('g');
}
} else if((G.qual==0))
} else if((G.qual==0)) {
if(v3d->twflag & V3D_USE_MANIPULATOR) {
if((v3d->twtype & V3D_MANIPULATOR_TRANSLATE)==0) {
v3d->twtype= V3D_MANIPULATOR_TRANSLATE;
doredraw= 1;
break;
}
}
#ifdef NEWTRANSFORM
Transform(TFM_TRANSLATION);
#else
transform('g');
#endif
}
break;
case HKEY:
if(G.obedit) {
@ -1485,19 +1493,35 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if (G.obedit->type==OB_MESH)
loopoperations(LOOP_CUT);
}
else if((G.qual==0))
else if((G.qual==0)) {
if(v3d->twflag & V3D_USE_MANIPULATOR) {
if((v3d->twtype & V3D_MANIPULATOR_ROTATE)==0) {
v3d->twtype= V3D_MANIPULATOR_ROTATE;
doredraw= 1;
break;
}
}
#ifdef NEWTRANSFORM
Transform(TFM_ROTATION);
#else
transform('r');
#endif
}
}
else if((G.qual==0))
else if((G.qual==0)) {
if(v3d->twflag & V3D_USE_MANIPULATOR) {
if((v3d->twtype & V3D_MANIPULATOR_ROTATE)==0) {
v3d->twtype= V3D_MANIPULATOR_ROTATE;
doredraw= 1;
break;
}
}
#ifdef NEWTRANSFORM
Transform(TFM_ROTATION);
#else
transform('r');
#endif
}
break;
case SKEY:
if(G.obedit) {
@ -1517,14 +1541,25 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
#endif
else if(G.qual==LR_SHIFTKEY)
snapmenu();
else if(G.qual==0)
else if(G.qual==0) {
if(v3d->twflag & V3D_USE_MANIPULATOR) {
if((v3d->twtype & V3D_MANIPULATOR_SCALE)==0) {
v3d->twtype= V3D_MANIPULATOR_SCALE;
doredraw= 1;
break;
}
}
#ifdef NEWTRANSFORM
Transform(TFM_RESIZE);
else if(G.qual==(LR_SHIFTKEY|LR_CTRLKEY))
Transform(TFM_TOSPHERE);
#else
transform('s');
#endif
}
else if(G.qual==(LR_SHIFTKEY|LR_CTRLKEY))
#ifdef NEWTRANSFORM
Transform(TFM_TOSPHERE);
#endif
}
else if(G.qual==LR_ALTKEY) {
if(okee("Clear size")) {
@ -1534,15 +1569,25 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
else if(G.qual==LR_SHIFTKEY) {
snapmenu();
}
else if((G.qual==0))
else if((G.qual==0)) {
if(v3d->twflag & V3D_USE_MANIPULATOR) {
if((v3d->twtype & V3D_MANIPULATOR_SCALE)==0) {
v3d->twtype= V3D_MANIPULATOR_SCALE;
doredraw= 1;
break;
}
}
#ifdef NEWTRANSFORM
Transform(TFM_RESIZE);
#else
transform('s');
#endif
}
#ifdef NEWTRANSFORM
else if(G.qual==(LR_SHIFTKEY|LR_CTRLKEY))
Transform(TFM_TOSPHERE);
else if(G.qual==(LR_CTRLKEY|LR_ALTKEY))
Transform(TFM_SHEAR);
#else
transform('s');
#endif
break;
case TKEY:

@ -1227,7 +1227,7 @@ static void createTransData(TransInfo *t)
t->mode &= ~TFM_TEX; // now becoming normal grab/rot/scale
}
else if (G.obpose) {
t->flag &= T_POSE;
t->flag |= T_POSE;
createTransPose();
}
else if (G.obedit) {
@ -1338,6 +1338,9 @@ void Transform(int mode)
case TFM_TILT:
initTilt(&Trans);
break;
case TFM_TRACKBALL:
initTrackball(&Trans);
break;
}
// Emptying event queue
@ -1572,8 +1575,6 @@ void Transform(int mode)
scrarea_queue_headredraw(curarea);
}
static void draw_nothing(TransInfo *t) {}
void ManipulatorTransform(int mode)
{
int ret_val = 0;
@ -1597,9 +1598,6 @@ void ManipulatorTransform(int mode)
if (Trans.total == 0)
return;
/* no drawing of constraint lines */
Trans.con.drawExtra= draw_nothing;
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
/* EVIL2: we gave as argument also texture space context bit... was cleared */
mode= Trans.mode;
@ -1617,8 +1615,12 @@ void ManipulatorTransform(int mode)
case TFM_RESIZE:
initResize(&Trans);
break;
case TFM_TRACKBALL:
initTrackball(&Trans);
break;
}
Trans.flag |= T_USES_MANIPULATOR;
Trans.redraw = 1;
while (ret_val == 0) {
@ -1915,6 +1917,8 @@ void initResize(TransInfo *t)
(Trans.center2d[0] - Trans.imval[0])*(Trans.center2d[0] - Trans.imval[0])
) );
if(Trans.fac==0.0f) Trans.fac= 1.0f; // prevent Inf
t->idx_max = 2;
t->num.idx_max = 2;
t->snap[0] = 0.0f;
@ -1960,13 +1964,19 @@ int Resize(TransInfo *t, short mval[2])
int i;
char str[50];
ratio = (float)sqrt( (float)
(
(t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
+
(t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
) ) / t->fac;
/* for manipulator, center handle, the scaling can't be done relative to center */
if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
ratio = 1.0f - ((t->center2d[0] - mval[0]) + (t->center2d[1] - mval[1]))/100.0f;
}
else {
ratio = (float)sqrt( (float)
(
(t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
+
(t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
) ) / t->fac;
}
size[0] = size[1] = size[2] = ratio;
snapGrid(t, size);
@ -1982,6 +1992,8 @@ int Resize(TransInfo *t, short mval[2])
t->con.applySize(t, NULL, mat);
}
Mat3CpyMat3(t->mat, mat); // used in manipulator
headerResize(t, size, str);
for(i = 0 ; i < t->total; i++, td++) {
@ -2064,7 +2076,7 @@ int Resize(TransInfo *t, short mval[2])
force_draw(0);
helpline (t->center);
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
return 1;
}
@ -2249,6 +2261,8 @@ int Rotation(TransInfo *t, short mval[2])
//printf("Axis %f %f %f\n", axis[0], axis[1], axis[2]);
VecRotToMat3(axis, final * td->factor, mat);
Mat3CpyMat3(t->mat, mat); // used in manipulator
for(i = 0 ; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
@ -2352,11 +2366,170 @@ int Rotation(TransInfo *t, short mval[2])
force_draw(0);
helpline (t->center);
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
return 1;
}
/* ************************** TRACKBALL *************************** */
void initTrackball(TransInfo *t)
{
t->idx_max = 1;
t->num.idx_max = 1;
t->snap[0] = 0.0f;
t->snap[1] = G.vd->grid * (float)((5.0/180)*M_PI);
t->snap[2] = t->snap[1] * 0.2f;
t->fac = 0;
t->transform = Trackball;
}
int Trackball(TransInfo *t, short mval[2])
{
TransData *td = t->data;
int i;
char str[50];
float vec[3], axis1[3], axis2[3];
float mat[3][3], totmat[3][3], smat[3][3];
float phi[2];
VECCOPY(axis1, G.vd->persinv[0]);
VECCOPY(axis2, G.vd->persinv[1]);
Normalise(axis1);
Normalise(axis2);
/* factore has to become setting or so */
phi[0]= .01*(float)( t->imval[1] - mval[1] );
phi[1]= .01*(float)( mval[0] - t->imval[0] );
//if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
//else t->fac += dphi;
snapGrid(t, phi);
if (hasNumInput(&t->num)) {
//char c[20];
//applyNumInput(&t->num, phi);
//outputNumInput(&(t->num), c);
//sprintf(str, "Trackball: %s %s", &c[0], t->proptext);
//final *= (float)(M_PI / 180.0);
}
else {
sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
}
VecRotToMat3(axis1, phi[0], smat);
VecRotToMat3(axis2, phi[1], totmat);
Mat3MulMat3(mat, smat, totmat);
Mat3CpyMat3(t->mat, mat); // used in manipulator
for(i = 0 ; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
break;
if (G.vd->around == V3D_LOCAL) {
VECCOPY(t->center, td->center);
}
if (t->flag & T_EDIT) {
Mat3MulMat3(totmat, mat, td->mtx);
Mat3MulMat3(smat, td->smtx, totmat);
VecSubf(vec, td->iloc, t->center);
Mat3MulVecfl(smat, vec);
VecAddf(td->loc, vec, t->center);
}
else {
float eul[3], fmat[3][3];
/* translation */
VecSubf(vec, td->center, t->center);
Mat3MulVecfl(mat, vec);
VecAddf(vec, vec, t->center);
/* vec now is the location where the object has to be */
VecSubf(vec, vec, td->center);
Mat3MulVecfl(td->smtx, vec);
VecAddf(td->loc, td->iloc, vec);
if(td->flag & TD_USEQUAT) {
float quat[4];
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
Mat3ToQuat(fmat, quat); // Actual transform
QuatMul(td->ext->quat, quat, td->ext->iquat);
}
else if ((G.vd->flag & V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
float obmat[3][3];
/* are there ipo keys? */
if(td->tdi) {
TransDataIpokey *tdi= td->tdi;
float rot[3];
/* calculate the total rotatation in eulers */
VecAddf(eul, td->ext->irot, td->ext->drot);
EulToMat3(eul, obmat);
/* mat = transform, obmat = object rotation */
Mat3MulMat3(fmat, mat, obmat);
Mat3ToEul(fmat, eul);
compatible_eul(eul, td->ext->irot);
/* correct back for delta rot */
if(tdi->flag & TOB_IPODROT) {
VecSubf(rot, eul, td->ext->irot);
}
else {
VecSubf(rot, eul, td->ext->drot);
}
VecMulf(rot, (float)(9.0/M_PI_2));
VecSubf(rot, rot, tdi->oldrot);
add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
}
else {
/* calculate the total rotatation in eulers */
VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
EulToMat3(eul, obmat);
/* mat = transform, obmat = object rotation */
Mat3MulMat3(fmat, mat, obmat);
Mat3ToEul(fmat, eul);
compatible_eul(eul, td->ext->irot);
/* correct back for delta rot */
VecSubf(eul, eul, td->ext->drot);
/* and apply */
VECCOPY(td->ext->rot, eul);
}
}
}
}
recalcData(t);
headerprint(str);
force_draw(0);
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
return 1;
}
/* ************************** TRANSLATION *************************** */
void initTranslation(TransInfo *t)

@ -146,8 +146,11 @@ typedef struct TransInfo {
#define T_EDIT 2
#define T_POSE 4
#define T_TEXTURE 8
// for manipulator exceptions, like scaling using center point, drawing help lines
#define T_USES_MANIPULATOR 128
/* transinfo->con->mode */
#define CON_APPLY 1
#define CON_AXIS0 2
#define CON_AXIS1 4
@ -186,5 +189,8 @@ int ShrinkFatten(TransInfo *t, short mval[2]);
void initTilt(TransInfo *t);
int Tilt(TransInfo *t, short mval[2]);
void initTrackball(TransInfo *t);
int Trackball(TransInfo *t, short mval[2]);
#endif

@ -589,6 +589,7 @@ void BIF_setSingleAxisConstraint(float vec[3]) {
Crossf(space[1], vec, v);
Crossf(space[2], vec, space[1]);
Mat3Ortho(space);
Mat3Ortho(space);
@ -603,6 +604,8 @@ void BIF_setSingleAxisConstraint(float vec[3]) {
t->con.applySize = applyAxisConstraintSize;
t->con.applyRot = applyAxisConstraintRot;
t->redraw = 1;
startConstraint(t);
}
void BIF_setDualAxisConstraint(float vec1[3], float vec2[3]) {
@ -612,7 +615,6 @@ void BIF_setDualAxisConstraint(float vec1[3], float vec2[3]) {
VECCOPY(space[0], vec1);
VECCOPY(space[1], vec2);
Crossf(space[2], space[0], space[1]);
Mat3Ortho(space);
Mat3CpyMat3(t->con.mtx, space);
@ -626,6 +628,8 @@ void BIF_setDualAxisConstraint(float vec1[3], float vec2[3]) {
t->con.applySize = applyAxisConstraintSize;
t->con.applyRot = applyAxisConstraintRot;
t->redraw = 1;
startConstraint(t);
}
@ -636,6 +640,8 @@ void BIF_drawConstraint(void)
if (!(tc->mode & CON_APPLY))
return;
if (t->flag & T_USES_MANIPULATOR)
return;
if (tc->drawExtra) {
tc->drawExtra(t);

@ -133,7 +133,7 @@ void recalcData(TransInfo *t)
for (i=0; i<t->total; i++, td++) {
chan = MEM_callocN (sizeof (bPoseChannel), "transPoseChannel");
if (t->mode == TFM_ROTATION) {
if (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) {
chan->flag |= POSE_ROT;
memcpy (chan->quat, td->ext->quat, sizeof (chan->quat));
}
@ -230,16 +230,17 @@ void recalcData(TransInfo *t)
base= FIRSTBASE;
while(base) {
if(base->flag & BA_DO_IPO) {
IpoCurve *icu;
base->object->ctime= -1234567.0;
icu= base->object->ipo->curve.first;
while(icu) {
calchandles_ipocurve(icu);
icu= icu->next;
}
if(base->object->ipo) {
IpoCurve *icu;
base->object->ctime= -1234567.0;
icu= base->object->ipo->curve.first;
while(icu) {
calchandles_ipocurve(icu);
icu= icu->next;
}
}
}
if(base->object->partype & PARSLOW) {
base->object->partype -= PARSLOW;
@ -639,8 +640,9 @@ void calculateCenter(TransInfo *t)
/* setting constraint center */
VECCOPY(t->con.center, t->center);
if(t->flag & T_EDIT) {
Mat4MulVecfl(G.obedit->obmat, t->con.center);
if(t->flag & (T_EDIT|T_POSE)) {
Object *ob= G.obedit?G.obedit:G.obpose;
Mat4MulVecfl(ob->obmat, t->con.center);
}
/* voor panning from cameraview */

@ -76,6 +76,7 @@
#include "BSE_edit.h"
#include "BSE_view.h"
#include "BDR_drawobject.h"
#include "blendef.h"
#include "transform.h"
@ -95,7 +96,14 @@
#define MAN_ROT_X 8
#define MAN_ROT_Y 16
#define MAN_ROT_Z 32
#define MAN_ROT_C 63
#define MAN_ROT_V 64
#define MAN_ROT_T 128
#define MAN_ROT_C 248
#define MAN_SCALE_X 256
#define MAN_SCALE_Y 512
#define MAN_SCALE_Z 1024
#define MAN_SCALE_C 1792
/* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING */
@ -273,9 +281,9 @@ static int calc_manipulator(ScrArea *sa)
/* global, local or normal orientation? */
if(ob) {
// local....
if(totsel==1 || v3d->around==V3D_LOCAL) {
Mat4CpyMat4(v3d->twmat, ob->obmat);
Mat4Ortho(v3d->twmat);
if(totsel==1 || v3d->around==V3D_LOCAL || G.obedit || G.obpose) {
//Mat4CpyMat4(v3d->twmat, ob->obmat);
//Mat4Ortho(v3d->twmat);
}
}
@ -298,7 +306,7 @@ static void manipulator_setcolor(char mode)
else {
switch(mode) {
case 'x':
glColor3ub(255, 100, 100);
glColor3ub(255, 0, 100);
break;
case 'y':
glColor3ub(100, 255, 100);
@ -324,14 +332,228 @@ static void manipulator_setcolor(char mode)
static int Gval= 0xFFFF; // defines drawmodus while moving...
static void draw_manipulator_rotate(float mat[][4])
{
double plane[4];
float size, vec[3], unitmat[4][4];
/* when called while moving in mixed mode, do not draw when... */
if((Gval & MAN_ROT_C)==0) return;
glDisable(GL_DEPTH_TEST);
Mat4One(unitmat);
/* Screen aligned help circle */
glPushMatrix();
glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
/* clipplane makes nice handles, calc here because of multmatrix but with translate! */
VECCOPY(plane, G.vd->viewinv[2]);
plane[3]= -0.001; // clip full circle
glClipPlane(GL_CLIP_PLANE0, plane);
glRotatef( -360.0*saacos(G.vd->viewquat[0])/M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
VECCOPY(vec, mat[0]);
size= Normalise(vec);
if((G.f & G_PICKSEL)==0) {
BIF_ThemeColorShade(TH_BACK, -30);
drawcircball(unitmat[3], size, unitmat);
}
/* Screen aligned view rot circle */
if(Gval & MAN_ROT_V) {
if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
BIF_ThemeColor(TH_TRANSFORM);
drawcircball(unitmat[3], 1.2*size, unitmat);
}
glPopMatrix();
/* apply the transform delta */
if(G.moving) {
float matt[4][4];
Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
Mat4MulMat34(matt, Trans.mat, mat);
mymultmatrix(matt);
}
else mymultmatrix(mat);
/* Trackball center */
if(Gval & MAN_ROT_T) {
GLUquadricObj *qobj = gluNewQuadric();
if(G.f & G_PICKSEL) glLoadName(MAN_ROT_T);
BIF_ThemeColor(TH_TRANSFORM);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3fv(G.vd->viewinv[2]);
glEnd();
BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
/* only has to be set here */
gluQuadricDrawStyle(qobj, GLU_FILL);
gluQuadricNormals(qobj, GLU_SMOOTH);
glEnable(GL_CULL_FACE); // backface removal
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glTranslatef(G.vd->viewinv[2][0], G.vd->viewinv[2][1], G.vd->viewinv[2][2]);
gluSphere(qobj, CYWID, 8, 6);
/* restore */
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glTranslatef(-G.vd->viewinv[2][0], -G.vd->viewinv[2][1], -G.vd->viewinv[2][2]);
gluDeleteQuadric(qobj);
}
glEnable(GL_CLIP_PLANE0);
/* Z circle */
if(Gval & MAN_ROT_Z) {
if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
manipulator_setcolor('z');
drawcircball(unitmat[3], 1.0, unitmat);
}
/* X circle */
if(Gval & MAN_ROT_X) {
if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
glRotatef(90.0, 0.0, 1.0, 0.0);
manipulator_setcolor('x');
drawcircball(unitmat[3], 1.0, unitmat);
glRotatef(-90.0, 0.0, 1.0, 0.0);
}
/* Y circle */
if(Gval & MAN_ROT_Y) {
if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
glRotatef(-90.0, 1.0, 0.0, 0.0);
manipulator_setcolor('y');
drawcircball(unitmat[3], 1.0, unitmat);
glRotatef(-90.0, 1.0, 0.0, 0.0);
}
glDisable(GL_CLIP_PLANE0);
myloadmatrix(G.vd->viewmat);
if(G.zbuf) glEnable(GL_DEPTH_TEST); // shouldn't be global, tsk!
}
static void draw_manipulator_scale(float mat[][4])
{
float cusize= CYWID*0.75;
/* when called while moving in mixed mode, do not draw when... */
if((Gval & MAN_SCALE_C)==0) return;
if(G.moving) {
float matt[4][4];
Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
Mat4MulMat34(matt, Trans.mat, mat);
mymultmatrix(matt);
}
else mymultmatrix(mat);
/* if not shiftkey, center point as first, for selectbuffer order */
if(G.f & G_PICKSEL) {
if(!(G.qual & LR_SHIFTKEY)) {
glLoadName(MAN_SCALE_C);
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
}
}
else {
float vec[3];
glDisable(GL_DEPTH_TEST);
/* axis */
glBegin(GL_LINES);
if(Gval & MAN_SCALE_X) {
manipulator_setcolor('x');
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
}
if(Gval & MAN_SCALE_Y) {
manipulator_setcolor('y');
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 1.0, 0.0);
}
if(Gval & MAN_SCALE_Z) {
manipulator_setcolor('z');
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 1.0);
}
glEnd();
/* only has to be set when not in picking */
glEnable(GL_CULL_FACE); // backface removal
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
/* center cube */
BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
drawsolidcube(cusize);
}
/* Z cube */
glTranslatef(0.0, 0.0, 1.0+cusize/2);
if(Gval & MAN_SCALE_Z) {
if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
manipulator_setcolor('Z');
drawsolidcube(cusize);
}
/* X cube */
glTranslatef(1.0+cusize/2, 0.0, -(1.0+cusize/2));
if(Gval & MAN_SCALE_X) {
if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
manipulator_setcolor('X');
drawsolidcube(cusize);
}
/* Y cube */
glTranslatef(-(1.0+cusize/2), 1.0+cusize/2, 0.0);
if(Gval & MAN_SCALE_Y) {
if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
manipulator_setcolor('Y');
drawsolidcube(cusize);
}
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
/* if shiftkey, center point as last, for selectbuffer order */
if(G.f & G_PICKSEL) {
if(G.qual & LR_SHIFTKEY) {
glTranslatef(0.0, -(1.0+cusize/2), 0.0);
glLoadName(MAN_SCALE_C);
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
}
}
myloadmatrix(G.vd->viewmat);
if(G.zbuf) glEnable(GL_DEPTH_TEST); // shouldn't be global, tsk!
}
static void draw_manipulator_translate(float mat[][4])
{
GLUquadricObj *qobj = gluNewQuadric();
/* when called while moving in mixed mode, do not draw when... */
if((Gval & MAN_TRANS_C)==0) return;
if(G.moving) glTranslatef(Trans.vec[0], Trans.vec[1], Trans.vec[2]);
glMultMatrixf(mat);
mymultmatrix(mat);
/* if not shiftkey, center point as first, for selectbuffer order */
if(G.f & G_PICKSEL) {
@ -482,14 +704,17 @@ void BIF_draw_manipulator(ScrArea *sa)
if(v3d->twflag & V3D_DRAW_MANIPULATOR) {
if(v3d->twmode==V3D_MANIPULATOR_TRANSLATE)
if(v3d->twtype & V3D_MANIPULATOR_ROTATE)
draw_manipulator_rotate(v3d->twmat);
if(v3d->twtype & V3D_MANIPULATOR_SCALE)
draw_manipulator_scale(v3d->twmat);
if(v3d->twtype & V3D_MANIPULATOR_TRANSLATE)
draw_manipulator_translate(v3d->twmat);
}
}
static int manipulator_selectbuf(ScrArea *sa)
static int manipulator_selectbuf(ScrArea *sa, float hotspot)
{
View3D *v3d= sa->spacedata.first;
rctf rect;
@ -499,37 +724,47 @@ static int manipulator_selectbuf(ScrArea *sa)
G.f |= G_PICKSEL;
getmouseco_areawin(mval);
rect.xmin= mval[0]-7;
rect.xmax= mval[0]+7;
rect.ymin= mval[1]-7;
rect.ymax= mval[1]+7;
rect.xmin= mval[0]-hotspot;
rect.xmax= mval[0]+hotspot;
rect.ymin= mval[1]-hotspot;
rect.ymax= mval[1]+hotspot;
/* get rid of overlay button matrix */
persp(PERSP_VIEW);
setwinmatrixview3d(&rect);
Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
glSelectBuffer( MAXPICKBUF, (GLuint *)buffer);
Mat4MulMat4(G.vd->persmat, G.vd->viewmat, sa->winmat);
glSelectBuffer( 32, buffer);
glRenderMode(GL_SELECT);
glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
glPushName(-1);
/* do the drawing */
if(v3d->twmode==V3D_MANIPULATOR_TRANSLATE)
if(v3d->twtype & V3D_MANIPULATOR_ROTATE)
draw_manipulator_rotate(v3d->twmat);
if(v3d->twtype & V3D_MANIPULATOR_SCALE)
draw_manipulator_scale(v3d->twmat);
if(v3d->twtype & V3D_MANIPULATOR_TRANSLATE)
draw_manipulator_translate(v3d->twmat);
glPopName(); /* see above (pushname) */
hits= glRenderMode(GL_RENDER);
G.f &= ~G_PICKSEL;
setwinmatrixview3d(0);
Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
Mat4MulMat4(G.vd->persmat, G.vd->viewmat, sa->winmat);
persp(PERSP_WIN);
if(hits>0) {
if(hits==1) return buffer[3];
else if(hits>1) {
/* we compare the two first in buffer, but exclude centers */
if(buffer[3]==MAN_TRANS_C || buffer[3]==MAN_SCALE_C);
else if(buffer[4+3]==MAN_TRANS_C || buffer[4+3]==MAN_SCALE_C);
else {
if(buffer[4+1] < buffer[1]) return buffer[4+3];
}
return buffer[3];
}
return 0;
@ -543,8 +778,14 @@ int BIF_do_manipulator(ScrArea *sa)
if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
// find the hotspots (Gval is for draw)
Gval=val= manipulator_selectbuf(sa);
// find the hotspots (Gval is for draw). first test narrow hotspot
// warning, Gval is ugly global defining how it draws, don't set it before doing select calls!
val= manipulator_selectbuf(sa, 7.0);
if(val) {
Gval= manipulator_selectbuf(sa, 3.0);
if(Gval) val= Gval;
else Gval= val;
}
switch(val) {
case MAN_TRANS_C:
@ -577,6 +818,56 @@ int BIF_do_manipulator(ScrArea *sa)
BIF_setSingleAxisConstraint(v3d->twmat[2]);
ManipulatorTransform(TFM_TRANSLATION);
break;
case MAN_SCALE_C:
ManipulatorTransform(TFM_RESIZE);
break;
case MAN_SCALE_X:
if(G.qual & LR_SHIFTKEY) {
Gval= MAN_SCALE_Y|MAN_SCALE_Z;
BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2]);
}
else
BIF_setSingleAxisConstraint(v3d->twmat[0]);
ManipulatorTransform(TFM_RESIZE);
break;
case MAN_SCALE_Y:
if(G.qual & LR_SHIFTKEY) {
Gval= MAN_SCALE_X|MAN_SCALE_Z;
BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2]);
}
else
BIF_setSingleAxisConstraint(v3d->twmat[1]);
ManipulatorTransform(TFM_RESIZE);
break;
case MAN_SCALE_Z:
if(G.qual & LR_SHIFTKEY) {
Gval= MAN_SCALE_X|MAN_SCALE_Y;
BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1]);
}
else
BIF_setSingleAxisConstraint(v3d->twmat[2]);
ManipulatorTransform(TFM_RESIZE);
break;
case MAN_ROT_X:
BIF_setSingleAxisConstraint(v3d->twmat[0]);
ManipulatorTransform(TFM_ROTATION);
break;
case MAN_ROT_Y:
BIF_setSingleAxisConstraint(v3d->twmat[1]);
ManipulatorTransform(TFM_ROTATION);
break;
case MAN_ROT_Z:
BIF_setSingleAxisConstraint(v3d->twmat[2]);
ManipulatorTransform(TFM_ROTATION);
break;
case MAN_ROT_T:
ManipulatorTransform(TFM_TRACKBALL);
break;
case MAN_ROT_V:
ManipulatorTransform(TFM_ROTATION);
break;
}
Gval= 0xFFFF;