Blender V2.61 - r43446

transform_constraints.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) 2001-2002 by NaN Holding BV.
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 <stdio.h>
00035 #include <string.h>
00036 #include <math.h>
00037 
00038 #ifndef WIN32
00039 #include <unistd.h>
00040 #else
00041 #include <io.h>
00042 #endif
00043 
00044 
00045 #include "DNA_object_types.h"
00046 #include "DNA_scene_types.h"
00047 #include "DNA_screen_types.h"
00048 #include "DNA_space_types.h"
00049 #include "DNA_view3d_types.h"
00050 
00051 #include "BIF_gl.h"
00052 #include "BIF_glutil.h"
00053 
00054 #include "BKE_context.h"
00055 
00056 
00057 #include "ED_image.h"
00058 #include "ED_view3d.h"
00059 
00060 #include "BLI_math.h"
00061 #include "BLI_utildefines.h"
00062 #include "BLI_string.h"
00063 
00064 //#include "blendef.h"
00065 //
00066 //#include "mydevice.h"
00067 
00068 #include "UI_resources.h"
00069 
00070 
00071 #include "transform.h"
00072 
00073 static void drawObjectConstraint(TransInfo *t);
00074 
00075 /* ************************** CONSTRAINTS ************************* */
00076 static void constraintAutoValues(TransInfo *t, float vec[3])
00077 {
00078     int mode = t->con.mode;
00079     if (mode & CON_APPLY)
00080     {
00081         float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
00082 
00083         if ((mode & CON_AXIS0) == 0)
00084         {
00085             vec[0] = nval;
00086         }
00087         if ((mode & CON_AXIS1) == 0)
00088         {
00089             vec[1] = nval;
00090         }
00091         if ((mode & CON_AXIS2) == 0)
00092         {
00093             vec[2] = nval;
00094         }
00095     }
00096 }
00097 
00098 void constraintNumInput(TransInfo *t, float vec[3])
00099 {
00100     int mode = t->con.mode;
00101     if (mode & CON_APPLY) {
00102         float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
00103 
00104         if (getConstraintSpaceDimension(t) == 2) {
00105             int axis = mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
00106             if (axis == (CON_AXIS0|CON_AXIS1)) {
00107                 /* vec[0] = vec[0]; */ /* same */
00108                 /* vec[1] = vec[1]; */ /* same */
00109                 vec[2] = nval;
00110             }
00111             else if (axis == (CON_AXIS1|CON_AXIS2)) {
00112                 vec[2] = vec[1];
00113                 vec[1] = vec[0];
00114                 vec[0] = nval;
00115             }
00116             else if (axis == (CON_AXIS0|CON_AXIS2)) {
00117                 /* vec[0] = vec[0]; */  /* same */
00118                 vec[2] = vec[1];
00119                 vec[1] = nval;
00120             }
00121         }
00122         else if (getConstraintSpaceDimension(t) == 1) {
00123             if (mode & CON_AXIS0) {
00124                 /* vec[0] = vec[0]; */ /* same */
00125                 vec[1] = nval;
00126                 vec[2] = nval;
00127             }
00128             else if (mode & CON_AXIS1) {
00129                 vec[1] = vec[0];
00130                 vec[0] = nval;
00131                 vec[2] = nval;
00132             }
00133             else if (mode & CON_AXIS2) {
00134                 vec[2] = vec[0];
00135                 vec[0] = nval;
00136                 vec[1] = nval;
00137             }
00138         }
00139     }
00140 }
00141 
00142 static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
00143 {
00144     int i = 0;
00145 
00146     mul_m3_v3(t->con.imtx, vec);
00147 
00148     snapGrid(t, vec);
00149 
00150     if (t->num.flag & T_NULL_ONE) {
00151         if (!(t->con.mode & CON_AXIS0))
00152             vec[0] = 1.0f;
00153 
00154         if (!(t->con.mode & CON_AXIS1))
00155             vec[1] = 1.0f;
00156 
00157         if (!(t->con.mode & CON_AXIS2))
00158             vec[2] = 1.0f;
00159     }
00160 
00161     if (hasNumInput(&t->num)) {
00162         applyNumInput(&t->num, vec);
00163         removeAspectRatio(t, vec);
00164         constraintNumInput(t, vec);
00165     }
00166 
00167     /* autovalues is operator param, use that directly but not if snapping is forced */
00168     if (t->flag & T_AUTOVALUES && (t->tsnap.status & SNAP_FORCED) == 0)
00169     {
00170         mul_v3_m3v3(vec, t->con.imtx, t->auto_values);
00171         constraintAutoValues(t, vec);
00172         /* inverse transformation at the end */
00173     }
00174 
00175     if (t->con.mode & CON_AXIS0) {
00176         pvec[i++] = vec[0];
00177     }
00178     if (t->con.mode & CON_AXIS1) {
00179         pvec[i++] = vec[1];
00180     }
00181     if (t->con.mode & CON_AXIS2) {
00182         pvec[i++] = vec[2];
00183     }
00184 
00185     mul_m3_v3(t->con.mtx, vec);
00186 }
00187 
00188 static void viewAxisCorrectCenter(TransInfo *t, float t_con_center[3])
00189 {
00190     if(t->spacetype == SPACE_VIEW3D) {
00191         // View3D *v3d = t->sa->spacedata.first;
00192         const float min_dist= 1.0f; // v3d->near;
00193         float dir[3];
00194         float l;
00195 
00196         sub_v3_v3v3(dir, t_con_center, t->viewinv[3]);
00197         if(dot_v3v3(dir, t->viewinv[2]) < 0.0f) {
00198             negate_v3(dir);
00199         }
00200         project_v3_v3v3(dir, dir, t->viewinv[2]);
00201 
00202         l= len_v3(dir);
00203 
00204         if(l < min_dist) {
00205             float diff[3];
00206             normalize_v3_v3(diff, t->viewinv[2]);
00207             mul_v3_fl(diff, min_dist - l);
00208 
00209             sub_v3_v3(t_con_center, diff);
00210         }
00211     }
00212 }
00213 
00214 static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3])
00215 {
00216     float norm[3], vec[3], factor, angle;
00217     float t_con_center[3];
00218 
00219     if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f)
00220         return;
00221 
00222     copy_v3_v3(t_con_center, t->con.center);
00223 
00224     /* checks for center being too close to the view center */
00225     viewAxisCorrectCenter(t, t_con_center);
00226     
00227     angle = fabsf(angle_v3v3(axis, t->viewinv[2]));
00228     if (angle > (float)M_PI / 2.0f) {
00229         angle = (float)M_PI - angle;
00230     }
00231     angle = RAD2DEGF(angle);
00232 
00233     /* For when view is parallel to constraint... will cause NaNs otherwise
00234        So we take vertical motion in 3D space and apply it to the
00235        constraint axis. Nice for camera grab + MMB */
00236     if(angle < 5.0f) {
00237         project_v3_v3v3(vec, in, t->viewinv[1]);
00238         factor = dot_v3v3(t->viewinv[1], vec) * 2.0f;
00239         /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
00240         if(factor<0.0f) factor*= -factor;
00241         else factor*= factor;
00242 
00243         copy_v3_v3(out, axis);
00244         normalize_v3(out);
00245         mul_v3_fl(out, -factor);    /* -factor makes move down going backwards */
00246     }
00247     else {
00248         float v[3], i1[3], i2[3];
00249         float v2[3], v4[3];
00250         float norm_center[3];
00251         float plane[3];
00252 
00253         getViewVector(t, t_con_center, norm_center);
00254         cross_v3_v3v3(plane, norm_center, axis);
00255 
00256         project_v3_v3v3(vec, in, plane);
00257         sub_v3_v3v3(vec, in, vec);
00258         
00259         add_v3_v3v3(v, vec, t_con_center);
00260         getViewVector(t, v, norm);
00261 
00262         /* give arbitrary large value if projection is impossible */
00263         factor = dot_v3v3(axis, norm);
00264         if (1.0f - fabsf(factor) < 0.0002f) {
00265             copy_v3_v3(out, axis);
00266             if (factor > 0) {
00267                 mul_v3_fl(out, 1000000000.0f);
00268             } else {
00269                 mul_v3_fl(out, -1000000000.0f);
00270             }
00271         } else {
00272             add_v3_v3v3(v2, t_con_center, axis);
00273             add_v3_v3v3(v4, v, norm);
00274             
00275             isect_line_line_v3(t_con_center, v2, v, v4, i1, i2);
00276             
00277             sub_v3_v3v3(v, i2, v);
00278     
00279             sub_v3_v3v3(out, i1, t_con_center);
00280 
00281             /* possible some values become nan when
00282              * viewpoint and object are both zero */
00283             if(!finite(out[0])) out[0]= 0.0f;
00284             if(!finite(out[1])) out[1]= 0.0f;
00285             if(!finite(out[2])) out[2]= 0.0f;
00286         }
00287     }
00288 }
00289 
00290 static void planeProjection(TransInfo *t, float in[3], float out[3])
00291 {
00292     float vec[3], factor, norm[3];
00293 
00294     add_v3_v3v3(vec, in, t->con.center);
00295     getViewVector(t, vec, norm);
00296 
00297     sub_v3_v3v3(vec, out, in);
00298 
00299     factor = dot_v3v3(vec, norm);
00300     if (fabs(factor) <= 0.001) {
00301         return; /* prevent divide by zero */
00302     }
00303     factor = dot_v3v3(vec, vec) / factor;
00304 
00305     copy_v3_v3(vec, norm);
00306     mul_v3_fl(vec, factor);
00307 
00308     add_v3_v3v3(out, in, vec);
00309 }
00310 
00311 /*
00312  * Generic callback for constant spacial constraints applied to linear motion
00313  *
00314  * The IN vector in projected into the constrained space and then further
00315  * projected along the view vector.
00316  * (in perspective mode, the view vector is relative to the position on screen)
00317  *
00318  */
00319 
00320 static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
00321 {
00322     copy_v3_v3(out, in);
00323     if (!td && t->con.mode & CON_APPLY) {
00324         mul_m3_v3(t->con.pmtx, out);
00325 
00326         // With snap, a projection is alright, no need to correct for view alignment
00327         if (!(t->tsnap.mode != SCE_SNAP_MODE_INCREMENT && activeSnap(t))) {
00328             if (getConstraintSpaceDimension(t) == 2) {
00329                 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
00330                     planeProjection(t, in, out);
00331                 }
00332             }
00333             else if (getConstraintSpaceDimension(t) == 1) {
00334                 float c[3];
00335 
00336                 if (t->con.mode & CON_AXIS0) {
00337                     copy_v3_v3(c, t->con.mtx[0]);
00338                 }
00339                 else if (t->con.mode & CON_AXIS1) {
00340                     copy_v3_v3(c, t->con.mtx[1]);
00341                 }
00342                 else if (t->con.mode & CON_AXIS2) {
00343                     copy_v3_v3(c, t->con.mtx[2]);
00344                 }
00345                 axisProjection(t, c, in, out);
00346             }
00347         }
00348         postConstraintChecks(t, out, pvec);
00349     }
00350 }
00351 
00352 /*
00353  * Generic callback for object based spatial constraints applied to linear motion
00354  *
00355  * At first, the following is applied to the first data in the array
00356  * The IN vector in projected into the constrained space and then further
00357  * projected along the view vector.
00358  * (in perspective mode, the view vector is relative to the position on screen)
00359  *
00360  * Further down, that vector is mapped to each data's space.
00361  */
00362 
00363 static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
00364 {
00365     copy_v3_v3(out, in);
00366     if (t->con.mode & CON_APPLY) {
00367         if (!td) {
00368             mul_m3_v3(t->con.pmtx, out);
00369             if (getConstraintSpaceDimension(t) == 2) {
00370                 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
00371                     planeProjection(t, in, out);
00372                 }
00373             }
00374             else if (getConstraintSpaceDimension(t) == 1) {
00375                 float c[3];
00376 
00377                 if (t->con.mode & CON_AXIS0) {
00378                     copy_v3_v3(c, t->con.mtx[0]);
00379                 }
00380                 else if (t->con.mode & CON_AXIS1) {
00381                     copy_v3_v3(c, t->con.mtx[1]);
00382                 }
00383                 else if (t->con.mode & CON_AXIS2) {
00384                     copy_v3_v3(c, t->con.mtx[2]);
00385                 }
00386                 axisProjection(t, c, in, out);
00387             }
00388             postConstraintChecks(t, out, pvec);
00389             copy_v3_v3(out, pvec);
00390         }
00391         else {
00392             int i=0;
00393 
00394             out[0] = out[1] = out[2] = 0.0f;
00395             if (t->con.mode & CON_AXIS0) {
00396                 out[0] = in[i++];
00397             }
00398             if (t->con.mode & CON_AXIS1) {
00399                 out[1] = in[i++];
00400             }
00401             if (t->con.mode & CON_AXIS2) {
00402                 out[2] = in[i++];
00403             }
00404             mul_m3_v3(td->axismtx, out);
00405         }
00406     }
00407 }
00408 
00409 /*
00410  * Generic callback for constant spacial constraints applied to resize motion
00411  *
00412  *
00413  */
00414 
00415 static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
00416 {
00417     if (!td && t->con.mode & CON_APPLY) {
00418         float tmat[3][3];
00419 
00420         if (!(t->con.mode & CON_AXIS0)) {
00421             smat[0][0] = 1.0f;
00422         }
00423         if (!(t->con.mode & CON_AXIS1)) {
00424             smat[1][1] = 1.0f;
00425         }
00426         if (!(t->con.mode & CON_AXIS2)) {
00427             smat[2][2] = 1.0f;
00428         }
00429 
00430         mul_m3_m3m3(tmat, smat, t->con.imtx);
00431         mul_m3_m3m3(smat, t->con.mtx, tmat);
00432     }
00433 }
00434 
00435 /*
00436  * Callback for object based spacial constraints applied to resize motion
00437  *
00438  *
00439  */
00440 
00441 static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
00442 {
00443     if (td && t->con.mode & CON_APPLY) {
00444         float tmat[3][3];
00445         float imat[3][3];
00446 
00447         invert_m3_m3(imat, td->axismtx);
00448 
00449         if (!(t->con.mode & CON_AXIS0)) {
00450             smat[0][0] = 1.0f;
00451         }
00452         if (!(t->con.mode & CON_AXIS1)) {
00453             smat[1][1] = 1.0f;
00454         }
00455         if (!(t->con.mode & CON_AXIS2)) {
00456             smat[2][2] = 1.0f;
00457         }
00458 
00459         mul_m3_m3m3(tmat, smat, imat);
00460         mul_m3_m3m3(smat, td->axismtx, tmat);
00461     }
00462 }
00463 
00464 /*
00465  * Generic callback for constant spacial constraints applied to rotations
00466  *
00467  * The rotation axis is copied into VEC.
00468  *
00469  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
00470  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
00471  *
00472  * The following only applies when CON_NOFLIP is not set.
00473  * The vector is then modified to always point away from the screen (in global space)
00474  * This insures that the rotation is always logically following the mouse.
00475  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
00476  */
00477 
00478 static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
00479 {
00480     if (!td && t->con.mode & CON_APPLY) {
00481         int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
00482 
00483         switch(mode) {
00484         case CON_AXIS0:
00485         case (CON_AXIS1|CON_AXIS2):
00486             copy_v3_v3(vec, t->con.mtx[0]);
00487             break;
00488         case CON_AXIS1:
00489         case (CON_AXIS0|CON_AXIS2):
00490             copy_v3_v3(vec, t->con.mtx[1]);
00491             break;
00492         case CON_AXIS2:
00493         case (CON_AXIS0|CON_AXIS1):
00494             copy_v3_v3(vec, t->con.mtx[2]);
00495             break;
00496         }
00497         /* don't flip axis if asked to or if num input */
00498         if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
00499             if (dot_v3v3(vec, t->viewinv[2]) > 0.0f) {
00500                 *angle = -(*angle);
00501             }
00502         }
00503     }
00504 }
00505 
00506 /*
00507  * Callback for object based spacial constraints applied to rotations
00508  *
00509  * The rotation axis is copied into VEC.
00510  *
00511  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
00512  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
00513  *
00514  * The following only applies when CON_NOFLIP is not set.
00515  * The vector is then modified to always point away from the screen (in global space)
00516  * This insures that the rotation is always logically following the mouse.
00517  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
00518  */
00519 
00520 static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
00521 {
00522     if (t->con.mode & CON_APPLY) {
00523         int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
00524 
00525         /* on setup call, use first object */
00526         if (td == NULL) {
00527             td= t->data;
00528         }
00529 
00530         switch(mode) {
00531         case CON_AXIS0:
00532         case (CON_AXIS1|CON_AXIS2):
00533             copy_v3_v3(vec, td->axismtx[0]);
00534             break;
00535         case CON_AXIS1:
00536         case (CON_AXIS0|CON_AXIS2):
00537             copy_v3_v3(vec, td->axismtx[1]);
00538             break;
00539         case CON_AXIS2:
00540         case (CON_AXIS0|CON_AXIS1):
00541             copy_v3_v3(vec, td->axismtx[2]);
00542             break;
00543         }
00544         if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
00545             if (dot_v3v3(vec, t->viewinv[2]) > 0.0f) {
00546                 *angle = -(*angle);
00547             }
00548         }
00549     }
00550 }
00551 
00552 /*--------------------- INTERNAL SETUP CALLS ------------------*/
00553 
00554 void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
00555 {
00556     BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
00557     copy_m3_m3(t->con.mtx, space);
00558     t->con.mode = mode;
00559     getConstraintMatrix(t);
00560 
00561     startConstraint(t);
00562 
00563     t->con.drawExtra = NULL;
00564     t->con.applyVec = applyAxisConstraintVec;
00565     t->con.applySize = applyAxisConstraintSize;
00566     t->con.applyRot = applyAxisConstraintRot;
00567     t->redraw = 1;
00568 }
00569 
00570 void setLocalConstraint(TransInfo *t, int mode, const char text[])
00571 {
00572     if (t->flag & T_EDIT) {
00573         float obmat[3][3];
00574         copy_m3_m4(obmat, t->scene->obedit->obmat);
00575         normalize_m3(obmat);
00576         setConstraint(t, obmat, mode, text);
00577     }
00578     else {
00579         if (t->total == 1) {
00580             setConstraint(t, t->data->axismtx, mode, text);
00581         }
00582         else {
00583             BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
00584             copy_m3_m3(t->con.mtx, t->data->axismtx);
00585             t->con.mode = mode;
00586             getConstraintMatrix(t);
00587 
00588             startConstraint(t);
00589 
00590             t->con.drawExtra = drawObjectConstraint;
00591             t->con.applyVec = applyObjectConstraintVec;
00592             t->con.applySize = applyObjectConstraintSize;
00593             t->con.applyRot = applyObjectConstraintRot;
00594             t->redraw = 1;
00595         }
00596     }
00597 }
00598 
00599 /*
00600     Set the constraint according to the user defined orientation
00601 
00602     ftext is a format string passed to BLI_snprintf. It will add the name of
00603     the orientation where %s is (logically).
00604 */
00605 void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[])
00606 {
00607     char text[40];
00608 
00609     switch(orientation) {
00610     case V3D_MANIP_GLOBAL:
00611         {
00612             float mtx[3][3]= MAT3_UNITY;
00613             BLI_snprintf(text, sizeof(text), ftext, "global");
00614             setConstraint(t, mtx, mode, text);
00615         }
00616         break;
00617     case V3D_MANIP_LOCAL:
00618         BLI_snprintf(text, sizeof(text), ftext, "local");
00619         setLocalConstraint(t, mode, text);
00620         break;
00621     case V3D_MANIP_NORMAL:
00622         BLI_snprintf(text, sizeof(text), ftext, "normal");
00623         setConstraint(t, t->spacemtx, mode, text);
00624         break;
00625     case V3D_MANIP_VIEW:
00626         BLI_snprintf(text, sizeof(text), ftext, "view");
00627         setConstraint(t, t->spacemtx, mode, text);
00628         break;
00629     case V3D_MANIP_GIMBAL:
00630         BLI_snprintf(text, sizeof(text), ftext, "gimbal");
00631         setConstraint(t, t->spacemtx, mode, text);
00632         break;
00633     default: /* V3D_MANIP_CUSTOM */
00634         BLI_snprintf(text, sizeof(text), ftext, t->spacename);
00635         setConstraint(t, t->spacemtx, mode, text);
00636         break;
00637     }
00638 
00639     t->con.orientation = orientation;
00640 
00641     t->con.mode |= CON_USER;
00642 }
00643 
00644 /*----------------- DRAWING CONSTRAINTS -------------------*/
00645 
00646 void drawConstraint(TransInfo *t)
00647 {
00648     TransCon *tc = &(t->con);
00649 
00650     if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE))
00651         return;
00652     if (!(tc->mode & CON_APPLY))
00653         return;
00654     if (t->flag & T_USES_MANIPULATOR)
00655         return;
00656     if (t->flag & T_NO_CONSTRAINT)
00657         return;
00658 
00659     /* nasty exception for Z constraint in camera view */
00660     // TRANSFORM_FIX_ME
00661 //  if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp==V3D_CAMOB)
00662 //      return;
00663 
00664     if (tc->drawExtra) {
00665         tc->drawExtra(t);
00666     }
00667     else {
00668         if (tc->mode & CON_SELECT) {
00669             float vec[3];
00670             char col2[3] = {255,255,255};
00671             int depth_test_enabled;
00672 
00673             convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1]));
00674             add_v3_v3(vec, tc->center);
00675 
00676             drawLine(t, tc->center, tc->mtx[0], 'X', 0);
00677             drawLine(t, tc->center, tc->mtx[1], 'Y', 0);
00678             drawLine(t, tc->center, tc->mtx[2], 'Z', 0);
00679 
00680             glColor3ubv((GLubyte *)col2);
00681 
00682             depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
00683             if(depth_test_enabled)
00684                 glDisable(GL_DEPTH_TEST);
00685 
00686             setlinestyle(1);
00687             glBegin(GL_LINE_STRIP);
00688                 glVertex3fv(tc->center);
00689                 glVertex3fv(vec);
00690             glEnd();
00691             setlinestyle(0);
00692 
00693             if(depth_test_enabled)
00694                 glEnable(GL_DEPTH_TEST);
00695         }
00696 
00697         if (tc->mode & CON_AXIS0) {
00698             drawLine(t, tc->center, tc->mtx[0], 'X', DRAWLIGHT);
00699         }
00700         if (tc->mode & CON_AXIS1) {
00701             drawLine(t, tc->center, tc->mtx[1], 'Y', DRAWLIGHT);
00702         }
00703         if (tc->mode & CON_AXIS2) {
00704             drawLine(t, tc->center, tc->mtx[2], 'Z', DRAWLIGHT);
00705         }
00706     }
00707 }
00708 
00709 /* called from drawview.c, as an extra per-window draw option */
00710 void drawPropCircle(const struct bContext *C, TransInfo *t)
00711 {
00712     if (t->flag & T_PROP_EDIT) {
00713         RegionView3D *rv3d = CTX_wm_region_view3d(C);
00714         float tmat[4][4], imat[4][4];
00715         float center[3];
00716 
00717         UI_ThemeColor(TH_GRID);
00718 
00719         if(t->spacetype == SPACE_VIEW3D && rv3d != NULL)
00720         {
00721             copy_m4_m4(tmat, rv3d->viewmat);
00722             invert_m4_m4(imat, tmat);
00723         }
00724         else
00725         {
00726             unit_m4(tmat);
00727             unit_m4(imat);
00728         }
00729 
00730         glPushMatrix();
00731 
00732         copy_v3_v3(center, t->center);
00733 
00734         if((t->spacetype == SPACE_VIEW3D) && t->obedit)
00735         {
00736             mul_m4_v3(t->obedit->obmat, center); /* because t->center is in local space */
00737         }
00738         else if(t->spacetype == SPACE_IMAGE)
00739         {
00740             float aspx, aspy;
00741 
00742             ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
00743             glScalef(1.0f/aspx, 1.0f/aspy, 1.0);
00744         }
00745 
00746         set_inverted_drawing(1);
00747         drawcircball(GL_LINE_LOOP, center, t->prop_size, imat);
00748         set_inverted_drawing(0);
00749 
00750         glPopMatrix();
00751     }
00752 }
00753 
00754 static void drawObjectConstraint(TransInfo *t)
00755 {
00756     int i;
00757     TransData * td = t->data;
00758 
00759     /* Draw the first one lighter because that's the one who controls the others.
00760        Meaning the transformation is projected on that one and just copied on the others
00761        constraint space.
00762        In a nutshell, the object with light axis is controlled by the user and the others follow.
00763        Without drawing the first light, users have little clue what they are doing.
00764      */
00765     if (t->con.mode & CON_AXIS0) {
00766         drawLine(t, td->ob->obmat[3], td->axismtx[0], 'X', DRAWLIGHT);
00767     }
00768     if (t->con.mode & CON_AXIS1) {
00769         drawLine(t, td->ob->obmat[3], td->axismtx[1], 'Y', DRAWLIGHT);
00770     }
00771     if (t->con.mode & CON_AXIS2) {
00772         drawLine(t, td->ob->obmat[3], td->axismtx[2], 'Z', DRAWLIGHT);
00773     }
00774 
00775     td++;
00776 
00777     for(i=1;i<t->total;i++,td++) {
00778         if (t->con.mode & CON_AXIS0) {
00779             drawLine(t, td->ob->obmat[3], td->axismtx[0], 'X', 0);
00780         }
00781         if (t->con.mode & CON_AXIS1) {
00782             drawLine(t, td->ob->obmat[3], td->axismtx[1], 'Y', 0);
00783         }
00784         if (t->con.mode & CON_AXIS2) {
00785             drawLine(t, td->ob->obmat[3], td->axismtx[2], 'Z', 0);
00786         }
00787     }
00788 }
00789 
00790 /*--------------------- START / STOP CONSTRAINTS ---------------------- */
00791 
00792 void startConstraint(TransInfo *t)
00793 {
00794     t->con.mode |= CON_APPLY;
00795     *t->con.text = ' ';
00796     t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
00797 }
00798 
00799 void stopConstraint(TransInfo *t)
00800 {
00801     t->con.mode &= ~(CON_APPLY|CON_SELECT);
00802     *t->con.text = '\0';
00803     t->num.idx_max = t->idx_max;
00804 }
00805 
00806 void getConstraintMatrix(TransInfo *t)
00807 {
00808     float mat[3][3];
00809     invert_m3_m3(t->con.imtx, t->con.mtx);
00810     unit_m3(t->con.pmtx);
00811 
00812     if (!(t->con.mode & CON_AXIS0)) {
00813         t->con.pmtx[0][0]       =
00814             t->con.pmtx[0][1]   =
00815             t->con.pmtx[0][2]   = 0.0f;
00816     }
00817 
00818     if (!(t->con.mode & CON_AXIS1)) {
00819         t->con.pmtx[1][0]       =
00820             t->con.pmtx[1][1]   =
00821             t->con.pmtx[1][2]   = 0.0f;
00822     }
00823 
00824     if (!(t->con.mode & CON_AXIS2)) {
00825         t->con.pmtx[2][0]       =
00826             t->con.pmtx[2][1]   =
00827             t->con.pmtx[2][2]   = 0.0f;
00828     }
00829 
00830     mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx);
00831     mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat);
00832 }
00833 
00834 /*------------------------- MMB Select -------------------------------*/
00835 
00836 void initSelectConstraint(TransInfo *t, float mtx[3][3])
00837 {
00838     copy_m3_m3(t->con.mtx, mtx);
00839     t->con.mode |= CON_APPLY;
00840     t->con.mode |= CON_SELECT;
00841 
00842     setNearestAxis(t);
00843     t->con.drawExtra = NULL;
00844     t->con.applyVec = applyAxisConstraintVec;
00845     t->con.applySize = applyAxisConstraintSize;
00846     t->con.applyRot = applyAxisConstraintRot;
00847 }
00848 
00849 void selectConstraint(TransInfo *t)
00850 {
00851     if (t->con.mode & CON_SELECT) {
00852         setNearestAxis(t);
00853         startConstraint(t);
00854     }
00855 }
00856 
00857 void postSelectConstraint(TransInfo *t)
00858 {
00859     if (!(t->con.mode & CON_SELECT))
00860         return;
00861 
00862     t->con.mode &= ~CON_AXIS0;
00863     t->con.mode &= ~CON_AXIS1;
00864     t->con.mode &= ~CON_AXIS2;
00865     t->con.mode &= ~CON_SELECT;
00866 
00867     setNearestAxis(t);
00868 
00869     startConstraint(t);
00870     t->redraw = 1;
00871 }
00872 
00873 static void setNearestAxis2d(TransInfo *t)
00874 {
00875     /* no correction needed... just use whichever one is lower */
00876     if ( abs(t->mval[0]-t->con.imval[0]) < abs(t->mval[1]-t->con.imval[1]) ) {
00877         t->con.mode |= CON_AXIS1;
00878         BLI_snprintf(t->con.text, sizeof(t->con.text), " along Y axis");
00879     }
00880     else {
00881         t->con.mode |= CON_AXIS0;
00882         BLI_snprintf(t->con.text, sizeof(t->con.text), " along X axis");
00883     }
00884 }
00885 
00886 static void setNearestAxis3d(TransInfo *t)
00887 {
00888     float zfac;
00889     float mvec[3], axis[3], proj[3];
00890     float len[3];
00891     int i, icoord[2];
00892 
00893     /* calculate mouse movement */
00894     mvec[0] = (float)(t->mval[0] - t->con.imval[0]);
00895     mvec[1] = (float)(t->mval[1] - t->con.imval[1]);
00896     mvec[2] = 0.0f;
00897 
00898     /* we need to correct axis length for the current zoomlevel of view,
00899        this to prevent projected values to be clipped behind the camera
00900        and to overflow the short integers.
00901        The formula used is a bit stupid, just a simplification of the substraction
00902        of two 2D points 30 pixels apart (that's the last factor in the formula) after
00903        projecting them with window_to_3d_delta and then get the length of that vector.
00904     */
00905     zfac= t->persmat[0][3]*t->center[0]+ t->persmat[1][3]*t->center[1]+ t->persmat[2][3]*t->center[2]+ t->persmat[3][3];
00906     zfac = len_v3(t->persinv[0]) * 2.0f/t->ar->winx * zfac * 30.0f;
00907 
00908     for (i = 0; i<3; i++) {
00909         copy_v3_v3(axis, t->con.mtx[i]);
00910 
00911         mul_v3_fl(axis, zfac);
00912         /* now we can project to get window coordinate */
00913         add_v3_v3(axis, t->con.center);
00914         projectIntView(t, axis, icoord);
00915 
00916         axis[0] = (float)(icoord[0] - t->center2d[0]);
00917         axis[1] = (float)(icoord[1] - t->center2d[1]);
00918         axis[2] = 0.0f;
00919 
00920         if (normalize_v3(axis) != 0.0f) {
00921             project_v3_v3v3(proj, mvec, axis);
00922             sub_v3_v3v3(axis, mvec, proj);
00923             len[i] = normalize_v3(axis);
00924         }
00925         else {
00926             len[i] = 10000000000.0f;
00927         }
00928     }
00929 
00930     if (len[0] <= len[1] && len[0] <= len[2]) {
00931         if (t->modifiers & MOD_CONSTRAINT_PLANE) {
00932             t->con.mode |= (CON_AXIS1|CON_AXIS2);
00933             BLI_snprintf(t->con.text, sizeof(t->con.text), " locking %s X axis", t->spacename);
00934         }
00935         else {
00936             t->con.mode |= CON_AXIS0;
00937             BLI_snprintf(t->con.text, sizeof(t->con.text), " along %s X axis", t->spacename);
00938         }
00939     }
00940     else if (len[1] <= len[0] && len[1] <= len[2]) {
00941         if (t->modifiers & MOD_CONSTRAINT_PLANE) {
00942             t->con.mode |= (CON_AXIS0|CON_AXIS2);
00943             BLI_snprintf(t->con.text, sizeof(t->con.text), " locking %s Y axis", t->spacename);
00944         }
00945         else {
00946             t->con.mode |= CON_AXIS1;
00947             BLI_snprintf(t->con.text, sizeof(t->con.text), " along %s Y axis", t->spacename);
00948         }
00949     }
00950     else if (len[2] <= len[1] && len[2] <= len[0]) {
00951         if (t->modifiers & MOD_CONSTRAINT_PLANE) {
00952             t->con.mode |= (CON_AXIS0|CON_AXIS1);
00953             BLI_snprintf(t->con.text, sizeof(t->con.text), " locking %s Z axis", t->spacename);
00954         }
00955         else {
00956             t->con.mode |= CON_AXIS2;
00957             BLI_snprintf(t->con.text, sizeof(t->con.text), " along %s Z axis", t->spacename);
00958         }
00959     }
00960 }
00961 
00962 void setNearestAxis(TransInfo *t)
00963 {
00964     /* clear any prior constraint flags */
00965     t->con.mode &= ~CON_AXIS0;
00966     t->con.mode &= ~CON_AXIS1;
00967     t->con.mode &= ~CON_AXIS2;
00968 
00969     /* constraint setting - depends on spacetype */
00970     if (t->spacetype == SPACE_VIEW3D) {
00971         /* 3d-view */
00972         setNearestAxis3d(t);
00973     }
00974     else {
00975         /* assume that this means a 2D-Editor */
00976         setNearestAxis2d(t);
00977     }
00978 
00979     getConstraintMatrix(t);
00980 }
00981 
00982 /*-------------- HELPER FUNCTIONS ----------------*/
00983 
00984 char constraintModeToChar(TransInfo *t)
00985 {
00986     if ((t->con.mode & CON_APPLY)==0) {
00987         return '\0';
00988     }
00989     switch (t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2)) {
00990     case (CON_AXIS0):
00991     case (CON_AXIS1|CON_AXIS2):
00992         return 'X';
00993     case (CON_AXIS1):
00994     case (CON_AXIS0|CON_AXIS2):
00995         return 'Y';
00996     case (CON_AXIS2):
00997     case (CON_AXIS0|CON_AXIS1):
00998         return 'Z';
00999     default:
01000         return '\0';
01001     }
01002 }
01003 
01004 
01005 int isLockConstraint(TransInfo *t)
01006 {
01007     int mode = t->con.mode;
01008 
01009     if ( (mode & (CON_AXIS0|CON_AXIS1)) == (CON_AXIS0|CON_AXIS1))
01010         return 1;
01011 
01012     if ( (mode & (CON_AXIS1|CON_AXIS2)) == (CON_AXIS1|CON_AXIS2))
01013         return 1;
01014 
01015     if ( (mode & (CON_AXIS0|CON_AXIS2)) == (CON_AXIS0|CON_AXIS2))
01016         return 1;
01017 
01018     return 0;
01019 }
01020 
01021 /*
01022  * Returns the dimension of the constraint space.
01023  *
01024  * For that reason, the flags always needs to be set to properly evaluate here,
01025  * even if they aren't actually used in the callback function. (Which could happen
01026  * for weird constraints not yet designed. Along a path for example.)
01027  */
01028 
01029 int getConstraintSpaceDimension(TransInfo *t)
01030 {
01031     int n = 0;
01032 
01033     if (t->con.mode & CON_AXIS0)
01034         n++;
01035 
01036     if (t->con.mode & CON_AXIS1)
01037         n++;
01038 
01039     if (t->con.mode & CON_AXIS2)
01040         n++;
01041 
01042     return n;
01043 /*
01044   Someone willing to do it criptically could do the following instead:
01045 
01046   return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
01047 
01048   Based on the assumptions that the axis flags are one after the other and start at 1
01049 */
01050 }