Blender V2.61 - r43446

transform_manipulator.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2005 Blender Foundation
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <math.h>
00036 #include <float.h>
00037 
00038 #ifndef WIN32
00039 #include <unistd.h>
00040 #else
00041 #include <io.h>
00042 #endif
00043 
00044 #include "MEM_guardedalloc.h"
00045 
00046 #include "DNA_armature_types.h"
00047 #include "DNA_curve_types.h"
00048 #include "DNA_lattice_types.h"
00049 #include "DNA_meta_types.h"
00050 #include "DNA_screen_types.h"
00051 #include "DNA_scene_types.h"
00052 #include "DNA_view3d_types.h"
00053 
00054 #include "RNA_access.h"
00055 
00056 #include "BKE_action.h"
00057 #include "BKE_context.h"
00058 #include "BKE_curve.h"
00059 #include "BKE_global.h"
00060 #include "BKE_mesh.h"
00061 #include "BKE_particle.h"
00062 #include "BKE_pointcache.h"
00063 
00064 #include "BLI_math.h"
00065 #include "BLI_editVert.h"
00066 #include "BLI_utildefines.h"
00067 
00068 #include "BIF_gl.h"
00069 
00070 #include "WM_api.h"
00071 #include "WM_types.h"
00072 
00073 #include "ED_armature.h"
00074 #include "ED_curve.h"
00075 #include "ED_mesh.h"
00076 #include "ED_particle.h"
00077 #include "ED_view3d.h"
00078 
00079 #include "UI_resources.h"
00080 
00081 /* local module include */
00082 #include "transform.h"
00083 
00084 /* return codes for select, and drawing flags */
00085 
00086 #define MAN_TRANS_X     1
00087 #define MAN_TRANS_Y     2
00088 #define MAN_TRANS_Z     4
00089 #define MAN_TRANS_C     7
00090 
00091 #define MAN_ROT_X       8
00092 #define MAN_ROT_Y       16
00093 #define MAN_ROT_Z       32
00094 #define MAN_ROT_V       64
00095 #define MAN_ROT_T       128
00096 #define MAN_ROT_C       248
00097 
00098 #define MAN_SCALE_X     256
00099 #define MAN_SCALE_Y     512
00100 #define MAN_SCALE_Z     1024
00101 #define MAN_SCALE_C     1792
00102 
00103 /* color codes */
00104 
00105 #define MAN_RGB     0
00106 #define MAN_GHOST   1
00107 #define MAN_MOVECOL 2
00108 
00109 /* transform widget center calc helper for below */
00110 static void calc_tw_center(Scene *scene, float *co)
00111 {
00112     float *twcent= scene->twcent;
00113     float *min= scene->twmin;
00114     float *max= scene->twmax;
00115 
00116     DO_MINMAX(co, min, max);
00117     add_v3_v3(twcent, co);
00118 }
00119 
00120 static void protectflag_to_drawflags(short protectflag, short *drawflags)
00121 {
00122     if(protectflag & OB_LOCK_LOCX)
00123         *drawflags &= ~MAN_TRANS_X;
00124     if(protectflag & OB_LOCK_LOCY)
00125         *drawflags &= ~MAN_TRANS_Y;
00126     if(protectflag & OB_LOCK_LOCZ)
00127         *drawflags &= ~MAN_TRANS_Z;
00128 
00129     if(protectflag & OB_LOCK_ROTX)
00130         *drawflags &= ~MAN_ROT_X;
00131     if(protectflag & OB_LOCK_ROTY)
00132         *drawflags &= ~MAN_ROT_Y;
00133     if(protectflag & OB_LOCK_ROTZ)
00134         *drawflags &= ~MAN_ROT_Z;
00135 
00136     if(protectflag & OB_LOCK_SCALEX)
00137         *drawflags &= ~MAN_SCALE_X;
00138     if(protectflag & OB_LOCK_SCALEY)
00139         *drawflags &= ~MAN_SCALE_Y;
00140     if(protectflag & OB_LOCK_SCALEZ)
00141         *drawflags &= ~MAN_SCALE_Z;
00142 }
00143 
00144 /* for pose mode */
00145 static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan)
00146 {
00147     Bone *bone= pchan->bone;
00148 
00149     if(bone) {
00150         if (bone->flag & BONE_TRANSFORM) {
00151             calc_tw_center(scene, pchan->pose_head);
00152             protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
00153         }
00154     }
00155 }
00156 
00157 /* for editmode*/
00158 static void stats_editbone(RegionView3D *rv3d, EditBone *ebo)
00159 {
00160     if (ebo->flag & BONE_EDITMODE_LOCKED)
00161         protectflag_to_drawflags(OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE, &rv3d->twdrawflag);
00162 }
00163 
00164 /* could move into BLI_math however this is only useful for display/editing purposes */
00165 static void axis_angle_to_gimbal_axis(float gmat[3][3], float axis[3], float angle)
00166 {
00167     /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
00168 
00169     float cross_vec[3];
00170     float quat[4];
00171 
00172     /* this is an un-scientific method to get a vector to cross with
00173      * XYZ intentionally YZX */
00174     cross_vec[0]= axis[1];
00175     cross_vec[1]= axis[2];
00176     cross_vec[2]= axis[0];
00177 
00178     /* X-axis */
00179     cross_v3_v3v3(gmat[0], cross_vec, axis);
00180     normalize_v3(gmat[0]);
00181     axis_angle_to_quat(quat, axis, angle);
00182     mul_qt_v3(quat, gmat[0]);
00183 
00184     /* Y-axis */
00185     axis_angle_to_quat(quat, axis, M_PI/2.0);
00186     copy_v3_v3(gmat[1], gmat[0]);
00187     mul_qt_v3(quat, gmat[1]);
00188 
00189     /* Z-axis */
00190     copy_v3_v3(gmat[2], axis);
00191 
00192     normalize_m3(gmat);
00193 }
00194 
00195 
00196 static int test_rotmode_euler(short rotmode)
00197 {
00198     return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0:1;
00199 }
00200 
00201 int gimbal_axis(Object *ob, float gmat[][3])
00202 {
00203     if (ob) {
00204         if(ob->mode & OB_MODE_POSE)
00205         {
00206             bPoseChannel *pchan= get_active_posechannel(ob);
00207 
00208             if(pchan) {
00209                 float mat[3][3], tmat[3][3], obmat[3][3];
00210                 if(test_rotmode_euler(pchan->rotmode)) {
00211                     eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
00212                 }
00213                 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
00214                     axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
00215                 }
00216                 else { /* quat */
00217                     return 0;
00218                 }
00219 
00220 
00221                 /* apply bone transformation */
00222                 mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
00223 
00224                 if (pchan->parent)
00225                 {
00226                     float parent_mat[3][3];
00227 
00228                     copy_m3_m4(parent_mat, pchan->parent->pose_mat);
00229                     mul_m3_m3m3(mat, parent_mat, tmat);
00230 
00231                     /* needed if object transformation isn't identity */
00232                     copy_m3_m4(obmat, ob->obmat);
00233                     mul_m3_m3m3(gmat, obmat, mat);
00234                 }
00235                 else
00236                 {
00237                     /* needed if object transformation isn't identity */
00238                     copy_m3_m4(obmat, ob->obmat);
00239                     mul_m3_m3m3(gmat, obmat, tmat);
00240                 }
00241 
00242                 normalize_m3(gmat);
00243                 return 1;
00244             }
00245         }
00246         else {
00247             if(test_rotmode_euler(ob->rotmode)) {
00248                 eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
00249             }
00250             else if(ob->rotmode == ROT_MODE_AXISANGLE) {
00251                 axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
00252             }
00253             else { /* quat */
00254                 return 0;
00255             }
00256 
00257             if (ob->parent)
00258             {
00259                 float parent_mat[3][3];
00260                 copy_m3_m4(parent_mat, ob->parent->obmat);
00261                 normalize_m3(parent_mat);
00262                 mul_m3_m3m3(gmat, parent_mat, gmat);
00263             }
00264             return 1;
00265         }
00266     }
00267 
00268     return 0;
00269 }
00270 
00271 
00272 /* centroid, boundbox, of selection */
00273 /* returns total items selected */
00274 int calc_manipulator_stats(const bContext *C)
00275 {
00276     ScrArea *sa= CTX_wm_area(C);
00277     ARegion *ar= CTX_wm_region(C);
00278     Scene *scene= CTX_data_scene(C);
00279     Object *obedit= CTX_data_edit_object(C);
00280     ToolSettings *ts = CTX_data_tool_settings(C);
00281     View3D *v3d= sa->spacedata.first;
00282     RegionView3D *rv3d= ar->regiondata;
00283     Base *base;
00284     Object *ob= OBACT;
00285     int a, totsel= 0;
00286 
00287     /* transform widget matrix */
00288     unit_m4(rv3d->twmat);
00289 
00290     rv3d->twdrawflag= 0xFFFF;
00291 
00292     /* transform widget centroid/center */
00293     scene->twcent[0]= scene->twcent[1]= scene->twcent[2]= 0.0f;
00294     INIT_MINMAX(scene->twmin, scene->twmax);
00295 
00296     if(obedit) {
00297         ob= obedit;
00298         if((ob->lay & v3d->lay)==0) return 0;
00299 
00300         if(obedit->type==OB_MESH) {
00301             EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
00302             EditVert *eve;
00303             EditSelection ese;
00304             float vec[3]= {0,0,0};
00305 
00306             /* USE LAST SELECTE WITH ACTIVE */
00307             if (v3d->around==V3D_ACTIVE && EM_get_actSelection(em, &ese)) {
00308                 EM_editselection_center(vec, &ese);
00309                 calc_tw_center(scene, vec);
00310                 totsel= 1;
00311             } else {
00312                 /* do vertices/edges/faces for center depending on selection
00313                    mode. note we can't use just vertex selection flag because
00314                    it is not flush down on changes */
00315                 if(ts->selectmode & SCE_SELECT_VERTEX) {
00316                     for(eve= em->verts.first; eve; eve= eve->next) {
00317                         if(eve->f & SELECT) {
00318                             totsel++;
00319                             calc_tw_center(scene, eve->co);
00320                         }
00321                     }
00322                 }
00323                 else if(ts->selectmode & SCE_SELECT_EDGE) {
00324                     EditEdge *eed;
00325 
00326                     for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
00327                     for(eed= em->edges.first; eed; eed= eed->next) {
00328                         if(eed->h==0 && (eed->f & SELECT)) {
00329                             if(!eed->v1->f1) {
00330                                 eed->v1->f1= 1;
00331                                 totsel++;
00332                                 calc_tw_center(scene, eed->v1->co);
00333                             }
00334                             if(!eed->v2->f1) {
00335                                 eed->v2->f1= 1;
00336                                 totsel++;
00337                                 calc_tw_center(scene, eed->v2->co);
00338                             }
00339                         }
00340                     }
00341                 }
00342                 else {
00343                     EditFace *efa;
00344 
00345                     for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
00346                     for(efa= em->faces.first; efa; efa= efa->next) {
00347                         if(efa->h==0 && (efa->f & SELECT)) {
00348                             if(!efa->v1->f1) {
00349                                 efa->v1->f1= 1;
00350                                 totsel++;
00351                                 calc_tw_center(scene, efa->v1->co);
00352                             }
00353                             if(!efa->v2->f1) {
00354                                 efa->v2->f1= 1;
00355                                 totsel++;
00356                                 calc_tw_center(scene, efa->v2->co);
00357                             }
00358                             if(!efa->v3->f1) {
00359                                 efa->v3->f1= 1;
00360                                 totsel++;
00361                                 calc_tw_center(scene, efa->v3->co);
00362                             }
00363                             if(efa->v4 && !efa->v4->f1) {
00364                                 efa->v4->f1= 1;
00365                                 totsel++;
00366                                 calc_tw_center(scene, efa->v4->co);
00367                             }
00368                         }
00369                     }
00370                 }
00371             }
00372         } /* end editmesh */
00373         else if (obedit->type==OB_ARMATURE){
00374             bArmature *arm= obedit->data;
00375             EditBone *ebo;
00376             for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
00377                 if(EBONE_VISIBLE(arm, ebo)) {
00378                     if (ebo->flag & BONE_TIPSEL) {
00379                         calc_tw_center(scene, ebo->tail);
00380                         totsel++;
00381                     }
00382                     if (ebo->flag & BONE_ROOTSEL) {
00383                         calc_tw_center(scene, ebo->head);
00384                         totsel++;
00385                     }
00386                     if (ebo->flag & BONE_SELECTED) {
00387                         stats_editbone(rv3d, ebo);
00388                     }
00389                 }
00390             }
00391         }
00392         else if ELEM(obedit->type, OB_CURVE, OB_SURF) {
00393             Curve *cu= obedit->data;
00394             float center[3];
00395 
00396             if (v3d->around==V3D_ACTIVE && ED_curve_actSelection(cu, center)) {
00397             calc_tw_center(scene, center);
00398                 totsel++;
00399             }
00400             else {
00401                 Nurb *nu;
00402                 BezTriple *bezt;
00403                 BPoint *bp;
00404                 ListBase *nurbs= curve_editnurbs(cu);
00405 
00406                 nu= nurbs->first;
00407                 while(nu) {
00408                     if(nu->type == CU_BEZIER) {
00409                         bezt= nu->bezt;
00410                         a= nu->pntsu;
00411                         while(a--) {
00412                             /* exceptions
00413                              * if handles are hidden then only check the center points.
00414                              * If the center knot is selected then only use this as the center point.
00415                              */
00416                             if (cu->drawflag & CU_HIDE_HANDLES) {
00417                                 if (bezt->f2 & SELECT) {
00418                                     calc_tw_center(scene, bezt->vec[1]);
00419                                     totsel++;
00420                                 }
00421                             }
00422                             else if (bezt->f2 & SELECT) {
00423                                 calc_tw_center(scene, bezt->vec[1]);
00424                                 totsel++;
00425                             }
00426                             else {
00427                                 if(bezt->f1) {
00428                                     calc_tw_center(scene, bezt->vec[0]);
00429                                     totsel++;
00430                                 }
00431                                 if(bezt->f3) {
00432                                     calc_tw_center(scene, bezt->vec[2]);
00433                                     totsel++;
00434                                 }
00435                             }
00436                             bezt++;
00437                         }
00438                     }
00439                     else {
00440                         bp= nu->bp;
00441                         a= nu->pntsu*nu->pntsv;
00442                         while(a--) {
00443                             if(bp->f1 & SELECT) {
00444                                 calc_tw_center(scene, bp->vec);
00445                                 totsel++;
00446                             }
00447                             bp++;
00448                         }
00449                     }
00450                     nu= nu->next;
00451                 }
00452             }
00453         }
00454         else if(obedit->type==OB_MBALL) {
00455             MetaBall *mb = (MetaBall*)obedit->data;
00456             MetaElem *ml /* , *ml_sel=NULL */ /* UNUSED */;
00457 
00458             ml= mb->editelems->first;
00459             while(ml) {
00460                 if(ml->flag & SELECT) {
00461                     calc_tw_center(scene, &ml->x);
00462                     /* ml_sel = ml; */ /* UNUSED */
00463                     totsel++;
00464                 }
00465                 ml= ml->next;
00466             }
00467         }
00468         else if(obedit->type==OB_LATTICE) {
00469             BPoint *bp;
00470             Lattice *lt= obedit->data;
00471 
00472             bp= lt->editlatt->latt->def;
00473 
00474             a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
00475             while(a--) {
00476                 if(bp->f1 & SELECT) {
00477                     calc_tw_center(scene, bp->vec);
00478                     totsel++;
00479                 }
00480                 bp++;
00481             }
00482         }
00483 
00484         /* selection center */
00485         if(totsel) {
00486             mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
00487             mul_m4_v3(obedit->obmat, scene->twcent);
00488             mul_m4_v3(obedit->obmat, scene->twmin);
00489             mul_m4_v3(obedit->obmat, scene->twmax);
00490         }
00491     }
00492     else if(ob && (ob->mode & OB_MODE_POSE)) {
00493         bPoseChannel *pchan;
00494         int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
00495 
00496         if((ob->lay & v3d->lay)==0) return 0;
00497 
00498         totsel = count_set_pose_transflags(&mode, 0, ob);
00499 
00500         if(totsel) {
00501             /* use channels to get stats */
00502             for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00503                 stats_pose(scene, rv3d, pchan);
00504             }
00505 
00506             mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
00507             mul_m4_v3(ob->obmat, scene->twcent);
00508             mul_m4_v3(ob->obmat, scene->twmin);
00509             mul_m4_v3(ob->obmat, scene->twmax);
00510         }
00511     }
00512     else if(ob && (ob->mode & OB_MODE_ALL_PAINT)) {
00513         ;
00514     }
00515     else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
00516         PTCacheEdit *edit= PE_get_current(scene, ob);
00517         PTCacheEditPoint *point;
00518         PTCacheEditKey *ek;
00519         int k;
00520 
00521         if(edit) {
00522             point = edit->points;
00523             for(a=0; a<edit->totpoint; a++,point++) {
00524                 if(point->flag & PEP_HIDE) continue;
00525 
00526                 for(k=0, ek=point->keys; k<point->totkey; k++, ek++) {
00527                     if(ek->flag & PEK_SELECT) {
00528                         calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co);
00529                         totsel++;
00530                     }
00531                 }
00532             }
00533 
00534             /* selection center */
00535             if(totsel)
00536                 mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
00537         }
00538     }
00539     else {
00540 
00541         /* we need the one selected object, if its not active */
00542         ob= OBACT;
00543         if(ob && !(ob->flag & SELECT)) ob= NULL;
00544 
00545         for(base= scene->base.first; base; base= base->next) {
00546             if TESTBASELIB(v3d, base) {
00547                 if(ob==NULL)
00548                     ob= base->object;
00549                 calc_tw_center(scene, base->object->obmat[3]);
00550                 protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
00551                 totsel++;
00552             }
00553         }
00554 
00555         /* selection center */
00556         if(totsel) {
00557             mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
00558         }
00559     }
00560 
00561     /* global, local or normal orientation? */
00562     if(ob && totsel) {
00563 
00564         switch(v3d->twmode) {
00565         
00566         case V3D_MANIP_GLOBAL:
00567             break; /* nothing to do */
00568 
00569         case V3D_MANIP_GIMBAL:
00570         {
00571             float mat[3][3];
00572             if (gimbal_axis(ob, mat)) {
00573                 copy_m4_m3(rv3d->twmat, mat);
00574                 break;
00575             }
00576             /* if not gimbal, fall through to normal */
00577         }
00578         case V3D_MANIP_NORMAL:
00579             if(obedit || ob->mode & OB_MODE_POSE) {
00580                 float mat[3][3];
00581                 ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE));
00582                 copy_m4_m3(rv3d->twmat, mat);
00583                 break;
00584             }
00585             /* no break we define 'normal' as 'local' in Object mode */
00586         case V3D_MANIP_LOCAL:
00587             copy_m4_m4(rv3d->twmat, ob->obmat);
00588             normalize_m4(rv3d->twmat);
00589             break;
00590 
00591         case V3D_MANIP_VIEW:
00592             {
00593                 float mat[3][3];
00594                 copy_m3_m4(mat, rv3d->viewinv);
00595                 normalize_m3(mat);
00596                 copy_m4_m3(rv3d->twmat, mat);
00597             }
00598             break;
00599         default: /* V3D_MANIP_CUSTOM */
00600             {
00601                 float mat[3][3];
00602                 applyTransformOrientation(C, mat, NULL);
00603                 copy_m4_m3(rv3d->twmat, mat);
00604                 break;
00605             }
00606         }
00607 
00608     }
00609 
00610     return totsel;
00611 }
00612 
00613 /* don't draw axis perpendicular to the view */
00614 static void test_manipulator_axis(const bContext *C)
00615 {
00616     RegionView3D *rv3d= CTX_wm_region_view3d(C);
00617     float angle;
00618     float vec[3];
00619 
00620     ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec);
00621 
00622     angle = fabs(angle_v3v3(rv3d->twmat[0], vec));
00623     if (angle > (float)M_PI / 2.0f) {
00624         angle = (float)M_PI - angle;
00625     }
00626     angle = rv3d->twangle[0] = RAD2DEGF(angle);
00627     if (angle < 5.0f) {
00628         rv3d->twdrawflag &= ~(MAN_TRANS_X|MAN_SCALE_X);
00629     }
00630 
00631     angle = fabs(angle_v3v3(rv3d->twmat[1], vec));
00632     if (angle > (float)M_PI / 2.0f) {
00633         angle = (float)M_PI - angle;
00634     }
00635     angle = rv3d->twangle[1] = RAD2DEGF(angle);
00636     if (angle < 5.0f) {
00637         rv3d->twdrawflag &= ~(MAN_TRANS_Y|MAN_SCALE_Y);
00638     }
00639 
00640     angle = fabs(angle_v3v3(rv3d->twmat[2], vec));
00641     if (angle > (float)M_PI / 2.0f) {
00642         angle = (float)M_PI - angle;
00643     }
00644     angle = rv3d->twangle[2] = RAD2DEGF(angle);
00645     if (angle < 5.0f) {
00646         rv3d->twdrawflag &= ~(MAN_TRANS_Z|MAN_SCALE_Z);
00647     }
00648 }
00649 
00650 
00651 /* ******************** DRAWING STUFFIES *********** */
00652 
00653 static float screen_aligned(RegionView3D *rv3d, float mat[][4])
00654 {
00655     glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
00656 
00657     /* sets view screen aligned */
00658     glRotatef( -360.0f*saacos(rv3d->viewquat[0])/(float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
00659 
00660     return len_v3(mat[0]); /* draw scale */
00661 }
00662 
00663 
00664 /* radring = radius of donut rings
00665    radhole = radius hole
00666    start = starting segment (based on nrings)
00667    end   = end segment
00668    nsides = amount of points in ring
00669    nrigns = amount of rings
00670 */
00671 static void partial_donut(float radring, float radhole, int start, int end, int nsides, int nrings)
00672 {
00673     float theta, phi, theta1;
00674     float cos_theta, sin_theta;
00675     float cos_theta1, sin_theta1;
00676     float ring_delta, side_delta;
00677     int i, j, docaps= 1;
00678 
00679     if(start==0 && end==nrings) docaps= 0;
00680 
00681     ring_delta= 2.0f*(float)M_PI/(float)nrings;
00682     side_delta= 2.0f*(float)M_PI/(float)nsides;
00683 
00684     theta= (float)M_PI+0.5f*ring_delta;
00685     cos_theta= (float)cos(theta);
00686     sin_theta= (float)sin(theta);
00687 
00688     for(i= nrings - 1; i >= 0; i--) {
00689         theta1= theta + ring_delta;
00690         cos_theta1= (float)cos(theta1);
00691         sin_theta1= (float)sin(theta1);
00692 
00693         if(docaps && i==start) {    // cap
00694             glBegin(GL_POLYGON);
00695             phi= 0.0;
00696             for(j= nsides; j >= 0; j--) {
00697                 float cos_phi, sin_phi, dist;
00698 
00699                 phi += side_delta;
00700                 cos_phi= (float)cos(phi);
00701                 sin_phi= (float)sin(phi);
00702                 dist= radhole + radring * cos_phi;
00703 
00704                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist,  radring * sin_phi);
00705             }
00706             glEnd();
00707         }
00708         if(i>=start && i<=end) {
00709             glBegin(GL_QUAD_STRIP);
00710             phi= 0.0;
00711             for(j= nsides; j >= 0; j--) {
00712                 float cos_phi, sin_phi, dist;
00713 
00714                 phi += side_delta;
00715                 cos_phi= (float)cos(phi);
00716                 sin_phi= (float)sin(phi);
00717                 dist= radhole + radring * cos_phi;
00718 
00719                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
00720                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
00721             }
00722             glEnd();
00723         }
00724 
00725         if(docaps && i==end) {  // cap
00726             glBegin(GL_POLYGON);
00727             phi= 0.0;
00728             for(j= nsides; j >= 0; j--) {
00729                 float cos_phi, sin_phi, dist;
00730 
00731                 phi -= side_delta;
00732                 cos_phi= (float)cos(phi);
00733                 sin_phi= (float)sin(phi);
00734                 dist= radhole + radring * cos_phi;
00735 
00736                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
00737             }
00738             glEnd();
00739         }
00740 
00741 
00742         theta= theta1;
00743         cos_theta= cos_theta1;
00744         sin_theta= sin_theta1;
00745     }
00746 }
00747 
00748 static char axisBlendAngle(float angle)
00749 {
00750     if (angle > 20)
00751         return 255;
00752 
00753     if (angle < 5)
00754         return 0;
00755 
00756     return (char)(255.0f * (angle - 5) / 15.0f);
00757 }
00758 
00759 /* three colors can be set;
00760    grey for ghosting
00761    moving: in transform theme color
00762    else the red/green/blue
00763 */
00764 static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned char alpha)
00765 {
00766     unsigned char col[4]= {0};
00767     col[3]= alpha;
00768 
00769     if(colcode==MAN_GHOST) {
00770         col[3]= 70;
00771     }
00772     else if(colcode==MAN_MOVECOL) {
00773         UI_GetThemeColor3ubv(TH_TRANSFORM, col);
00774     }
00775     else {
00776         switch(axis) {
00777         case 'C':
00778             UI_GetThemeColor3ubv(TH_TRANSFORM, col);
00779             if(v3d->twmode == V3D_MANIP_LOCAL) {
00780                 col[0]= col[0]>200?255:col[0]+55;
00781                 col[1]= col[1]>200?255:col[1]+55;
00782                 col[2]= col[2]>200?255:col[2]+55;
00783             }
00784             else if(v3d->twmode == V3D_MANIP_NORMAL) {
00785                 col[0]= col[0]<55?0:col[0]-55;
00786                 col[1]= col[1]<55?0:col[1]-55;
00787                 col[2]= col[2]<55?0:col[2]-55;
00788             }
00789             break;
00790         case 'X':
00791             col[0]= 220;
00792             break;
00793         case 'Y':
00794             col[1]= 220;
00795             break;
00796         case 'Z':
00797             col[0]= 30;
00798             col[1]= 30;
00799             col[2]= 220;
00800             break;
00801         default:
00802             BLI_assert(!"invalid axis arg");
00803         }
00804     }
00805 
00806     glColor4ubv(col);
00807 }
00808 
00809 /* viewmatrix should have been set OK, also no shademode! */
00810 static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode, int flagx, int flagy, int flagz)
00811 {
00812 
00813     /* axes */
00814     if(flagx) {
00815         manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
00816         if(flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
00817         else if(flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
00818         glBegin(GL_LINES);
00819         glVertex3f(0.2f, 0.0f, 0.0f);
00820         glVertex3f(1.0f, 0.0f, 0.0f);
00821         glEnd();
00822     }
00823     if(flagy) {
00824         if(flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
00825         else if(flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
00826         manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
00827         glBegin(GL_LINES);
00828         glVertex3f(0.0f, 0.2f, 0.0f);
00829         glVertex3f(0.0f, 1.0f, 0.0f);
00830         glEnd();
00831     }
00832     if(flagz) {
00833         if(flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
00834         else if(flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
00835         manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
00836         glBegin(GL_LINES);
00837         glVertex3f(0.0f, 0.0f, 0.2f);
00838         glVertex3f(0.0f, 0.0f, 1.0f);
00839         glEnd();
00840     }
00841 }
00842 
00843 static void preOrthoFront(int ortho, float twmat[][4], int axis)
00844 {
00845     if (ortho == 0) {
00846         float omat[4][4];
00847         copy_m4_m4(omat, twmat);
00848         orthogonalize_m4(omat, axis);
00849         glPushMatrix();
00850         glMultMatrixf(omat);
00851         glFrontFace(is_negative_m4(omat) ? GL_CW:GL_CCW);
00852     }
00853 }
00854 
00855 static void postOrtho(int ortho)
00856 {
00857     if (ortho == 0) {
00858         glPopMatrix();
00859     }
00860 }
00861 
00862 static void draw_manipulator_rotate(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo)
00863 {
00864     GLUquadricObj *qobj;
00865     double plane[4];
00866     float matt[4][4];
00867     float size, unitmat[4][4];
00868     float cywid= 0.33f*0.01f*(float)U.tw_handlesize;
00869     float cusize= cywid*0.65f;
00870     int arcs= (G.rt!=2);
00871     int colcode;
00872     int ortho;
00873 
00874     if(moving) colcode= MAN_MOVECOL;
00875     else colcode= MAN_RGB;
00876 
00877     /* when called while moving in mixed mode, do not draw when... */
00878     if((drawflags & MAN_ROT_C)==0) return;
00879 
00880     /* Init stuff */
00881     glDisable(GL_DEPTH_TEST);
00882     unit_m4(unitmat);
00883 
00884     qobj= gluNewQuadric();
00885     gluQuadricDrawStyle(qobj, GLU_FILL);
00886 
00887     /* prepare for screen aligned draw */
00888     size= len_v3(rv3d->twmat[0]);
00889     glPushMatrix();
00890     glTranslatef(rv3d->twmat[3][0], rv3d->twmat[3][1], rv3d->twmat[3][2]);
00891 
00892     if(arcs) {
00893         /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
00894         VECCOPY(plane, rv3d->viewinv[2]); /* float -> double */
00895         plane[3]= -0.02f*size; // clip just a bit more
00896         glClipPlane(GL_CLIP_PLANE0, plane);
00897     }
00898     /* sets view screen aligned */
00899     glRotatef( -360.0f*saacos(rv3d->viewquat[0])/(float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
00900 
00901     /* Screen aligned help circle */
00902     if(arcs) {
00903         if((G.f & G_PICKSEL)==0) {
00904             UI_ThemeColorShade(TH_BACK, -30);
00905             drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
00906         }
00907     }
00908 
00909     /* Screen aligned trackball rot circle */
00910     if(drawflags & MAN_ROT_T) {
00911         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_T);
00912 
00913         UI_ThemeColor(TH_TRANSFORM);
00914         drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
00915     }
00916 
00917     /* Screen aligned view rot circle */
00918     if(drawflags & MAN_ROT_V) {
00919         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
00920         UI_ThemeColor(TH_TRANSFORM);
00921         drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat);
00922 
00923         if(moving) {
00924             float vec[3];
00925             vec[0]= 0; // XXX (float)(t->imval[0] - t->center2d[0]);
00926             vec[1]= 0; // XXX (float)(t->imval[1] - t->center2d[1]);
00927             vec[2]= 0.0f;
00928             normalize_v3(vec);
00929             mul_v3_fl(vec, 1.2f*size);
00930             glBegin(GL_LINES);
00931             glVertex3f(0.0f, 0.0f, 0.0f);
00932             glVertex3fv(vec);
00933             glEnd();
00934         }
00935     }
00936     glPopMatrix();
00937 
00938 
00939     ortho = is_orthogonal_m4(rv3d->twmat);
00940     
00941     /* apply the transform delta */
00942     if(moving) {
00943         copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
00944         // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
00945         if (ortho) {
00946             glMultMatrixf(matt);
00947             glFrontFace(is_negative_m4(matt) ? GL_CW:GL_CCW);
00948         }
00949     }
00950     else {
00951         if (ortho) {
00952             glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW:GL_CCW);
00953             glMultMatrixf(rv3d->twmat);
00954         }
00955     }
00956 
00957     /* axes */
00958     if(arcs==0) {
00959         if(!(G.f & G_PICKSEL)) {
00960             if( (combo & V3D_MANIP_SCALE)==0) {
00961                 /* axis */
00962                 if( (drawflags & MAN_ROT_X) || (moving && (drawflags & MAN_ROT_Z)) ) {
00963                     preOrthoFront(ortho, rv3d->twmat, 2);
00964                     manipulator_setcolor(v3d, 'X', colcode, 255);
00965                     glBegin(GL_LINES);
00966                     glVertex3f(0.2f, 0.0f, 0.0f);
00967                     glVertex3f(1.0f, 0.0f, 0.0f);
00968                     glEnd();
00969                     postOrtho(ortho);
00970                 }
00971                 if( (drawflags & MAN_ROT_Y) || (moving && (drawflags & MAN_ROT_X)) ) {
00972                     preOrthoFront(ortho, rv3d->twmat, 0);
00973                     manipulator_setcolor(v3d, 'Y', colcode, 255);
00974                     glBegin(GL_LINES);
00975                     glVertex3f(0.0f, 0.2f, 0.0f);
00976                     glVertex3f(0.0f, 1.0f, 0.0f);
00977                     glEnd();
00978                     postOrtho(ortho);
00979                 }
00980                 if( (drawflags & MAN_ROT_Z) || (moving && (drawflags & MAN_ROT_Y)) ) {
00981                     preOrthoFront(ortho, rv3d->twmat, 1);
00982                     manipulator_setcolor(v3d, 'Z', colcode, 255);
00983                     glBegin(GL_LINES);
00984                     glVertex3f(0.0f, 0.0f, 0.2f);
00985                     glVertex3f(0.0f, 0.0f, 1.0f);
00986                     glEnd();
00987                     postOrtho(ortho);
00988                 }
00989             }
00990         }
00991     }
00992 
00993     if(arcs==0 && moving) {
00994 
00995         /* Z circle */
00996         if(drawflags & MAN_ROT_Z) {
00997             preOrthoFront(ortho, matt, 2);
00998             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
00999             manipulator_setcolor(v3d, 'Z', colcode, 255);
01000             drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
01001             postOrtho(ortho);
01002         }
01003         /* X circle */
01004         if(drawflags & MAN_ROT_X) {
01005             preOrthoFront(ortho, matt, 0);
01006             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
01007             glRotatef(90.0, 0.0, 1.0, 0.0);
01008             manipulator_setcolor(v3d, 'X', colcode, 255);
01009             drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
01010             glRotatef(-90.0, 0.0, 1.0, 0.0);
01011             postOrtho(ortho);
01012         }
01013         /* Y circle */
01014         if(drawflags & MAN_ROT_Y) {
01015             preOrthoFront(ortho, matt, 1);
01016             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
01017             glRotatef(-90.0, 1.0, 0.0, 0.0);
01018             manipulator_setcolor(v3d, 'Y', colcode, 255);
01019             drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
01020             glRotatef(90.0, 1.0, 0.0, 0.0);
01021             postOrtho(ortho);
01022         }
01023 
01024         if(arcs) glDisable(GL_CLIP_PLANE0);
01025     }
01026     // donut arcs
01027     if(arcs) {
01028         glEnable(GL_CLIP_PLANE0);
01029 
01030         /* Z circle */
01031         if(drawflags & MAN_ROT_Z) {
01032             preOrthoFront(ortho, rv3d->twmat, 2);
01033             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
01034             manipulator_setcolor(v3d, 'Z', colcode, 255);
01035             partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
01036             postOrtho(ortho);
01037         }
01038         /* X circle */
01039         if(drawflags & MAN_ROT_X) {
01040             preOrthoFront(ortho, rv3d->twmat, 0);
01041             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
01042             glRotatef(90.0, 0.0, 1.0, 0.0);
01043             manipulator_setcolor(v3d, 'X', colcode, 255);
01044             partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
01045             glRotatef(-90.0, 0.0, 1.0, 0.0);
01046             postOrtho(ortho);
01047         }
01048         /* Y circle */
01049         if(drawflags & MAN_ROT_Y) {
01050             preOrthoFront(ortho, rv3d->twmat, 1);
01051             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
01052             glRotatef(-90.0, 1.0, 0.0, 0.0);
01053             manipulator_setcolor(v3d, 'Y', colcode, 255);
01054             partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
01055             glRotatef(90.0, 1.0, 0.0, 0.0);
01056             postOrtho(ortho);
01057         }
01058 
01059         glDisable(GL_CLIP_PLANE0);
01060     }
01061 
01062     if(arcs==0) {
01063 
01064         /* Z handle on X axis */
01065         if(drawflags & MAN_ROT_Z) {
01066             preOrthoFront(ortho, rv3d->twmat, 2);
01067             glPushMatrix();
01068             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
01069             manipulator_setcolor(v3d, 'Z', colcode, 255);
01070 
01071             partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
01072 
01073             glPopMatrix();
01074             postOrtho(ortho);
01075         }
01076 
01077         /* Y handle on X axis */
01078         if(drawflags & MAN_ROT_Y) {
01079             preOrthoFront(ortho, rv3d->twmat, 1);
01080             glPushMatrix();
01081             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
01082             manipulator_setcolor(v3d, 'Y', colcode, 255);
01083 
01084             glRotatef(90.0, 1.0, 0.0, 0.0);
01085             glRotatef(90.0, 0.0, 0.0, 1.0);
01086             partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
01087 
01088             glPopMatrix();
01089             postOrtho(ortho);
01090         }
01091 
01092         /* X handle on Z axis */
01093         if(drawflags & MAN_ROT_X) {
01094             preOrthoFront(ortho, rv3d->twmat, 0);
01095             glPushMatrix();
01096             if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
01097             manipulator_setcolor(v3d, 'X', colcode, 255);
01098 
01099             glRotatef(-90.0, 0.0, 1.0, 0.0);
01100             glRotatef(90.0, 0.0, 0.0, 1.0);
01101             partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
01102 
01103             glPopMatrix();
01104             postOrtho(ortho);
01105         }
01106 
01107     }
01108 
01109     /* restore */
01110     glLoadMatrixf(rv3d->viewmat);
01111     gluDeleteQuadric(qobj);
01112     if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
01113 
01114 }
01115 
01116 static void drawsolidcube(float size)
01117 {
01118     static float cube[8][3] = {
01119     {-1.0, -1.0, -1.0},
01120     {-1.0, -1.0,  1.0},
01121     {-1.0,  1.0,  1.0},
01122     {-1.0,  1.0, -1.0},
01123     { 1.0, -1.0, -1.0},
01124     { 1.0, -1.0,  1.0},
01125     { 1.0,  1.0,  1.0},
01126     { 1.0,  1.0, -1.0}, };
01127     float n[3];
01128 
01129     glPushMatrix();
01130     glScalef(size, size, size);
01131 
01132     n[0]=0; n[1]=0; n[2]=0;
01133     glBegin(GL_QUADS);
01134     n[0]= -1.0;
01135     glNormal3fv(n);
01136     glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
01137     n[0]=0;
01138     glEnd();
01139 
01140     glBegin(GL_QUADS);
01141     n[1]= -1.0;
01142     glNormal3fv(n);
01143     glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
01144     n[1]=0;
01145     glEnd();
01146 
01147     glBegin(GL_QUADS);
01148     n[0]= 1.0;
01149     glNormal3fv(n);
01150     glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
01151     n[0]=0;
01152     glEnd();
01153 
01154     glBegin(GL_QUADS);
01155     n[1]= 1.0;
01156     glNormal3fv(n);
01157     glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
01158     n[1]=0;
01159     glEnd();
01160 
01161     glBegin(GL_QUADS);
01162     n[2]= 1.0;
01163     glNormal3fv(n);
01164     glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
01165     n[2]=0;
01166     glEnd();
01167 
01168     glBegin(GL_QUADS);
01169     n[2]= -1.0;
01170     glNormal3fv(n);
01171     glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
01172     glEnd();
01173 
01174     glPopMatrix();
01175 }
01176 
01177 
01178 static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode)
01179 {
01180     float cywid= 0.25f*0.01f*(float)U.tw_handlesize;
01181     float cusize= cywid*0.75f, dz;
01182 
01183     /* when called while moving in mixed mode, do not draw when... */
01184     if((drawflags & MAN_SCALE_C)==0) return;
01185 
01186     glDisable(GL_DEPTH_TEST);
01187 
01188     /* not in combo mode */
01189     if( (combo & (V3D_MANIP_TRANSLATE|V3D_MANIP_ROTATE))==0) {
01190         float size, unitmat[4][4];
01191         int shift= 0; // XXX
01192 
01193         /* center circle, do not add to selection when shift is pressed (planar constraint)  */
01194         if( (G.f & G_PICKSEL) && shift==0) glLoadName(MAN_SCALE_C);
01195 
01196         manipulator_setcolor(v3d, 'C', colcode, 255);
01197         glPushMatrix();
01198         size= screen_aligned(rv3d, rv3d->twmat);
01199         unit_m4(unitmat);
01200         drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
01201         glPopMatrix();
01202 
01203         dz= 1.0;
01204     }
01205     else dz= 1.0f-4.0f*cusize;
01206 
01207     if(moving) {
01208         float matt[4][4];
01209 
01210         copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
01211         // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
01212         glMultMatrixf(matt);
01213         glFrontFace(is_negative_m4(matt) ? GL_CW:GL_CCW);
01214     }
01215     else {
01216         glMultMatrixf(rv3d->twmat);
01217         glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW:GL_CCW);
01218     }
01219 
01220     /* axis */
01221 
01222     /* in combo mode, this is always drawn as first type */
01223     draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z);
01224 
01225     /* Z cube */
01226     glTranslatef(0.0, 0.0, dz);
01227     if(drawflags & MAN_SCALE_Z) {
01228         if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
01229         manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
01230         drawsolidcube(cusize);
01231     }
01232     /* X cube */
01233     glTranslatef(dz, 0.0, -dz);
01234     if(drawflags & MAN_SCALE_X) {
01235         if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
01236         manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
01237         drawsolidcube(cusize);
01238     }
01239     /* Y cube */
01240     glTranslatef(-dz, dz, 0.0);
01241     if(drawflags & MAN_SCALE_Y) {
01242         if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
01243         manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
01244         drawsolidcube(cusize);
01245     }
01246 
01247     /* if shiftkey, center point as last, for selectbuffer order */
01248     if(G.f & G_PICKSEL) {
01249         int shift= 0; // XXX
01250 
01251         if(shift) {
01252             glTranslatef(0.0, -dz, 0.0);
01253             glLoadName(MAN_SCALE_C);
01254             glBegin(GL_POINTS);
01255             glVertex3f(0.0, 0.0, 0.0);
01256             glEnd();
01257         }
01258     }
01259 
01260     /* restore */
01261     glLoadMatrixf(rv3d->viewmat);
01262 
01263     if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
01264     glFrontFace(GL_CCW);
01265 }
01266 
01267 
01268 static void draw_cone(GLUquadricObj *qobj, float len, float width)
01269 {
01270     glTranslatef(0.0, 0.0, -0.5f*len);
01271     gluCylinder(qobj, width, 0.0, len, 8, 1);
01272     gluQuadricOrientation(qobj, GLU_INSIDE);
01273     gluDisk(qobj, 0.0, width, 8, 1);
01274     gluQuadricOrientation(qobj, GLU_OUTSIDE);
01275     glTranslatef(0.0, 0.0, 0.5f*len);
01276 }
01277 
01278 static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
01279 {
01280 
01281     width*= 0.8f;   // just for beauty
01282 
01283     glTranslatef(0.0, 0.0, -0.5f*len);
01284     gluCylinder(qobj, width, width, len, 8, 1);
01285     gluQuadricOrientation(qobj, GLU_INSIDE);
01286     gluDisk(qobj, 0.0, width, 8, 1);
01287     gluQuadricOrientation(qobj, GLU_OUTSIDE);
01288     glTranslatef(0.0, 0.0, len);
01289     gluDisk(qobj, 0.0, width, 8, 1);
01290     glTranslatef(0.0, 0.0, -0.5f*len);
01291 }
01292 
01293 
01294 static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUSED(moving), int drawflags, int combo, int colcode)
01295 {
01296     GLUquadricObj *qobj;
01297     float cylen= 0.01f*(float)U.tw_handlesize;
01298     float cywid= 0.25f*cylen, dz, size;
01299     float unitmat[4][4];
01300     int shift= 0; // XXX
01301 
01302     /* when called while moving in mixed mode, do not draw when... */
01303     if((drawflags & MAN_TRANS_C)==0) return;
01304 
01305     // XXX if(moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]);
01306     glDisable(GL_DEPTH_TEST);
01307 
01308     qobj= gluNewQuadric();
01309     gluQuadricDrawStyle(qobj, GLU_FILL);
01310 
01311     /* center circle, do not add to selection when shift is pressed (planar constraint) */
01312     if( (G.f & G_PICKSEL) && shift==0) glLoadName(MAN_TRANS_C);
01313 
01314     manipulator_setcolor(v3d, 'C', colcode, 255);
01315     glPushMatrix();
01316     size= screen_aligned(rv3d, rv3d->twmat);
01317     unit_m4(unitmat);
01318     drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
01319     glPopMatrix();
01320 
01321     /* and now apply matrix, we move to local matrix drawing */
01322     glMultMatrixf(rv3d->twmat);
01323 
01324     /* axis */
01325     glLoadName(-1);
01326 
01327     // translate drawn as last, only axis when no combo with scale, or for ghosting
01328     if((combo & V3D_MANIP_SCALE)==0 || colcode==MAN_GHOST)
01329         draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z);
01330 
01331 
01332     /* offset in combo mode, for rotate a bit more */
01333     if(combo & (V3D_MANIP_ROTATE)) dz= 1.0f+2.0f*cylen;
01334     else if(combo & (V3D_MANIP_SCALE)) dz= 1.0f+0.5f*cylen;
01335     else dz= 1.0f;
01336 
01337     /* Z Cone */
01338     glTranslatef(0.0, 0.0, dz);
01339     if(drawflags & MAN_TRANS_Z) {
01340         if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
01341         manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
01342         draw_cone(qobj, cylen, cywid);
01343     }
01344     /* X Cone */
01345     glTranslatef(dz, 0.0, -dz);
01346     if(drawflags & MAN_TRANS_X) {
01347         if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
01348         glRotatef(90.0, 0.0, 1.0, 0.0);
01349         manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
01350         draw_cone(qobj, cylen, cywid);
01351         glRotatef(-90.0, 0.0, 1.0, 0.0);
01352     }
01353     /* Y Cone */
01354     glTranslatef(-dz, dz, 0.0);
01355     if(drawflags & MAN_TRANS_Y) {
01356         if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
01357         glRotatef(-90.0, 1.0, 0.0, 0.0);
01358         manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
01359         draw_cone(qobj, cylen, cywid);
01360     }
01361 
01362     gluDeleteQuadric(qobj);
01363     glLoadMatrixf(rv3d->viewmat);
01364 
01365     if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
01366 
01367 }
01368 
01369 static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode)
01370 {
01371     GLUquadricObj *qobj;
01372     float size;
01373     float cylen= 0.01f*(float)U.tw_handlesize;
01374     float cywid= 0.25f*cylen;
01375 
01376     /* when called while moving in mixed mode, do not draw when... */
01377     if((drawflags & MAN_ROT_C)==0) return;
01378 
01379     /* prepare for screen aligned draw */
01380     glPushMatrix();
01381     size= screen_aligned(rv3d, rv3d->twmat);
01382 
01383     glDisable(GL_DEPTH_TEST);
01384 
01385     qobj= gluNewQuadric();
01386 
01387     /* Screen aligned view rot circle */
01388     if(drawflags & MAN_ROT_V) {
01389         float unitmat[4][4]= MAT4_UNITY;
01390 
01391         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
01392         UI_ThemeColor(TH_TRANSFORM);
01393         drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat);
01394 
01395         if(moving) {
01396             float vec[3];
01397             vec[0]= 0; // XXX (float)(t->imval[0] - t->center2d[0]);
01398             vec[1]= 0; // XXX (float)(t->imval[1] - t->center2d[1]);
01399             vec[2]= 0.0f;
01400             normalize_v3(vec);
01401             mul_v3_fl(vec, 1.2f*size);
01402             glBegin(GL_LINES);
01403             glVertex3f(0.0, 0.0, 0.0);
01404             glVertex3fv(vec);
01405             glEnd();
01406         }
01407     }
01408     glPopMatrix();
01409 
01410     /* apply the transform delta */
01411     if(moving) {
01412         float matt[4][4];
01413         copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
01414         // XXX      if (t->flag & T_USES_MANIPULATOR) {
01415         // XXX          mul_m4_m3m4(matt, t->mat, rv3d->twmat);
01416         // XXX }
01417         glMultMatrixf(matt);
01418     }
01419     else {
01420         glMultMatrixf(rv3d->twmat);
01421     }
01422 
01423     glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW:GL_CCW);
01424 
01425     /* axis */
01426     if( (G.f & G_PICKSEL)==0 ) {
01427 
01428         // only draw axis when combo didn't draw scale axes
01429         if((combo & V3D_MANIP_SCALE)==0)
01430             draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z);
01431 
01432         /* only has to be set when not in picking */
01433         gluQuadricDrawStyle(qobj, GLU_FILL);
01434     }
01435 
01436     /* Z cyl */
01437     glTranslatef(0.0, 0.0, 1.0);
01438     if(drawflags & MAN_ROT_Z) {
01439         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
01440         manipulator_setcolor(v3d, 'Z', colcode, 255);
01441         draw_cylinder(qobj, cylen, cywid);
01442     }
01443     /* X cyl */
01444     glTranslatef(1.0, 0.0, -1.0);
01445     if(drawflags & MAN_ROT_X) {
01446         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
01447         glRotatef(90.0, 0.0, 1.0, 0.0);
01448         manipulator_setcolor(v3d, 'X', colcode, 255);
01449         draw_cylinder(qobj, cylen, cywid);
01450         glRotatef(-90.0, 0.0, 1.0, 0.0);
01451     }
01452     /* Y cylinder */
01453     glTranslatef(-1.0, 1.0, 0.0);
01454     if(drawflags & MAN_ROT_Y) {
01455         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
01456         glRotatef(-90.0, 1.0, 0.0, 0.0);
01457         manipulator_setcolor(v3d, 'Y', colcode, 255);
01458         draw_cylinder(qobj, cylen, cywid);
01459     }
01460 
01461     /* restore */
01462 
01463     gluDeleteQuadric(qobj);
01464     glLoadMatrixf(rv3d->viewmat);
01465 
01466     if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
01467 
01468 }
01469 
01470 
01471 /* ********************************************* */
01472 
01473 /* main call, does calc centers & orientation too */
01474 /* uses global G.moving */
01475 static int drawflags= 0xFFFF;       // only for the calls below, belongs in scene...?
01476 
01477 void BIF_draw_manipulator(const bContext *C)
01478 {
01479     ScrArea *sa= CTX_wm_area(C);
01480     ARegion *ar= CTX_wm_region(C);
01481     Scene *scene= CTX_data_scene(C);
01482     View3D *v3d= sa->spacedata.first;
01483     RegionView3D *rv3d= ar->regiondata;
01484     int totsel;
01485 
01486     if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
01487 //  if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return;
01488 
01489 //  if(G.moving==0) {
01490     {
01491         v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
01492 
01493         totsel= calc_manipulator_stats(C);
01494         if(totsel==0) return;
01495 
01496         v3d->twflag |= V3D_DRAW_MANIPULATOR;
01497 
01498         /* now we can define center */
01499         switch(v3d->around) {
01500         case V3D_CENTER:
01501         case V3D_ACTIVE:
01502             rv3d->twmat[3][0]= (scene->twmin[0] + scene->twmax[0])/2.0f;
01503             rv3d->twmat[3][1]= (scene->twmin[1] + scene->twmax[1])/2.0f;
01504             rv3d->twmat[3][2]= (scene->twmin[2] + scene->twmax[2])/2.0f;
01505             if(v3d->around==V3D_ACTIVE && scene->obedit==NULL) {
01506                 Object *ob= OBACT;
01507                 if(ob && !(ob->mode & OB_MODE_POSE))
01508                     copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
01509             }
01510             break;
01511         case V3D_LOCAL:
01512         case V3D_CENTROID:
01513             copy_v3_v3(rv3d->twmat[3], scene->twcent);
01514             break;
01515         case V3D_CURSOR:
01516             copy_v3_v3(rv3d->twmat[3], give_cursor(scene, v3d));
01517             break;
01518         }
01519 
01520         mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size * 5.0f);
01521     }
01522 
01523     test_manipulator_axis(C);
01524     drawflags= rv3d->twdrawflag;    /* set in calc_manipulator_stats */
01525 
01526     if(v3d->twflag & V3D_DRAW_MANIPULATOR) {
01527 
01528         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
01529         glEnable(GL_BLEND);
01530         if(v3d->twtype & V3D_MANIP_ROTATE) {
01531 
01532             if(G.rt==3) {
01533                 if(G.moving) draw_manipulator_rotate_cyl(v3d, rv3d, 1, drawflags, v3d->twtype, MAN_MOVECOL);
01534                 else draw_manipulator_rotate_cyl(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
01535             }
01536             else
01537                 draw_manipulator_rotate(v3d, rv3d, 0 /* G.moving*/, drawflags, v3d->twtype);
01538         }
01539         if(v3d->twtype & V3D_MANIP_SCALE) {
01540             draw_manipulator_scale(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
01541         }
01542         if(v3d->twtype & V3D_MANIP_TRANSLATE) {
01543             draw_manipulator_translate(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
01544         }
01545 
01546         glDisable(GL_BLEND);
01547     }
01548 }
01549 
01550 static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], float hotspot)
01551 {
01552     View3D *v3d= sa->spacedata.first;
01553     RegionView3D *rv3d= ar->regiondata;
01554     rctf rect;
01555     GLuint buffer[64];      // max 4 items per select, so large enuf
01556     short hits;
01557     extern void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); // XXX check a bit later on this... (ton)
01558 
01559     G.f |= G_PICKSEL;
01560 
01561     rect.xmin= mval[0]-hotspot;
01562     rect.xmax= mval[0]+hotspot;
01563     rect.ymin= mval[1]-hotspot;
01564     rect.ymax= mval[1]+hotspot;
01565 
01566     setwinmatrixview3d(ar, v3d, &rect);
01567     mult_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
01568 
01569     glSelectBuffer( 64, buffer);
01570     glRenderMode(GL_SELECT);
01571     glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
01572     glPushName(-2);
01573 
01574     /* do the drawing */
01575     if(v3d->twtype & V3D_MANIP_ROTATE) {
01576         if(G.rt==3) draw_manipulator_rotate_cyl(v3d, rv3d, 0, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB);
01577         else draw_manipulator_rotate(v3d, rv3d, 0, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype);
01578     }
01579     if(v3d->twtype & V3D_MANIP_SCALE)
01580         draw_manipulator_scale(v3d, rv3d, 0, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB);
01581     if(v3d->twtype & V3D_MANIP_TRANSLATE)
01582         draw_manipulator_translate(v3d, rv3d, 0, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB);
01583 
01584     glPopName();
01585     hits= glRenderMode(GL_RENDER);
01586 
01587     G.f &= ~G_PICKSEL;
01588     setwinmatrixview3d(ar, v3d, NULL);
01589     mult_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
01590 
01591     if(hits==1) return buffer[3];
01592     else if(hits>1) {
01593         GLuint val, dep, mindep=0, mindeprot=0, minval=0, minvalrot=0;
01594         int a;
01595 
01596         /* we compare the hits in buffer, but value centers highest */
01597         /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */
01598 
01599         for(a=0; a<hits; a++) {
01600             dep= buffer[4*a + 1];
01601             val= buffer[4*a + 3];
01602 
01603             if(val==MAN_TRANS_C) return MAN_TRANS_C;
01604             else if(val==MAN_SCALE_C) return MAN_SCALE_C;
01605             else {
01606                 if(val & MAN_ROT_C) {
01607                     if(minvalrot==0 || dep<mindeprot) {
01608                         mindeprot= dep;
01609                         minvalrot= val;
01610                     }
01611                 }
01612                 else {
01613                     if(minval==0 || dep<mindep) {
01614                         mindep= dep;
01615                         minval= val;
01616                     }
01617                 }
01618             }
01619         }
01620 
01621         if(minval)
01622             return minval;
01623         else
01624             return minvalrot;
01625     }
01626     return 0;
01627 }
01628 
01629 
01630 /* return 0; nothing happened */
01631 int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op)
01632 {
01633     ScrArea *sa= CTX_wm_area(C);
01634     View3D *v3d= sa->spacedata.first;
01635     ARegion *ar= CTX_wm_region(C);
01636     int constraint_axis[3] = {0, 0, 0};
01637     int val;
01638     int shift = event->shift;
01639 
01640     if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
01641     if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
01642 
01643     /* Force orientation */
01644     RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode);
01645 
01646     // find the hotspots first test narrow hotspot
01647     val= manipulator_selectbuf(sa, ar, event->mval, 0.5f*(float)U.tw_hotspot);
01648     if(val) {
01649 
01650         // drawflags still global, for drawing call above
01651         drawflags= manipulator_selectbuf(sa, ar, event->mval, 0.2f*(float)U.tw_hotspot);
01652         if(drawflags==0) drawflags= val;
01653 
01654         if (drawflags & MAN_TRANS_C) {
01655             switch(drawflags) {
01656             case MAN_TRANS_C:
01657                 break;
01658             case MAN_TRANS_X:
01659                 if(shift) {
01660                     constraint_axis[1] = 1;
01661                     constraint_axis[2] = 1;
01662                 }
01663                 else
01664                     constraint_axis[0] = 1;
01665                 break;
01666             case MAN_TRANS_Y:
01667                 if(shift) {
01668                     constraint_axis[0] = 1;
01669                     constraint_axis[2] = 1;
01670                 }
01671                 else
01672                     constraint_axis[1] = 1;
01673                 break;
01674             case MAN_TRANS_Z:
01675                 if(shift) {
01676                     constraint_axis[0] = 1;
01677                     constraint_axis[1] = 1;
01678                 }
01679                 else
01680                     constraint_axis[2] = 1;
01681                 break;
01682             }
01683             RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
01684             WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr);
01685             //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_translate", 0), event, op->ptr, NULL, FALSE);
01686         }
01687         else if (drawflags & MAN_SCALE_C) {
01688             switch(drawflags) {
01689             case MAN_SCALE_X:
01690                 if(shift) {
01691                     constraint_axis[1] = 1;
01692                     constraint_axis[2] = 1;
01693                 }
01694                 else
01695                     constraint_axis[0] = 1;
01696                 break;
01697             case MAN_SCALE_Y:
01698                 if(shift) {
01699                     constraint_axis[0] = 1;
01700                     constraint_axis[2] = 1;
01701                 }
01702                 else
01703                     constraint_axis[1] = 1;
01704                 break;
01705             case MAN_SCALE_Z:
01706                 if(shift) {
01707                     constraint_axis[0] = 1;
01708                     constraint_axis[1] = 1;
01709                 }
01710                 else
01711                     constraint_axis[2] = 1;
01712                 break;
01713             }
01714             RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
01715             WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr);
01716             //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_resize", 0), event, op->ptr, NULL, FALSE);
01717         }
01718         else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
01719             WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, op->ptr);
01720             //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, op->ptr, NULL, FALSE);
01721         }
01722         else if (drawflags & MAN_ROT_C) {
01723             switch(drawflags) {
01724             case MAN_ROT_X:
01725                 constraint_axis[0] = 1;
01726                 break;
01727             case MAN_ROT_Y:
01728                 constraint_axis[1] = 1;
01729                 break;
01730             case MAN_ROT_Z:
01731                 constraint_axis[2] = 1;
01732                 break;
01733             }
01734             RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
01735             WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr);
01736             //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_rotate", 0), event, op->ptr, NULL, FALSE);
01737         }
01738     }
01739     /* after transform, restore drawflags */
01740     drawflags= 0xFFFF;
01741 
01742     return val;
01743 }
01744