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