svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r20849:20855
[blender.git] / source / blender / editors / transform / transform_constraints.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <math.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifndef WIN32
40 #include <unistd.h>
41 #else
42 #include <io.h>
43 #endif
44
45 #include "MEM_guardedalloc.h"
46
47 #include "DNA_action_types.h"
48 #include "DNA_armature_types.h"
49 #include "DNA_camera_types.h"
50 #include "DNA_curve_types.h"
51 #include "DNA_effect_types.h"
52 #include "DNA_image_types.h"
53 #include "DNA_ipo_types.h"
54 #include "DNA_key_types.h"
55 #include "DNA_lamp_types.h"
56 #include "DNA_lattice_types.h"
57 #include "DNA_mesh_types.h"
58 #include "DNA_meshdata_types.h"
59 #include "DNA_meta_types.h"
60 #include "DNA_object_types.h"
61 #include "DNA_scene_types.h"
62 #include "DNA_screen_types.h"
63 #include "DNA_space_types.h"
64 #include "DNA_view3d_types.h"
65
66 #include "BIF_gl.h"
67 #include "BIF_glutil.h"
68
69 #include "BKE_context.h"
70 #include "BKE_global.h"
71 #include "BKE_utildefines.h"
72
73 #include "ED_image.h"
74 #include "ED_view3d.h"
75
76 #include "BLI_arithb.h"
77
78 //#include "blendef.h"
79 //
80 //#include "mydevice.h"
81
82 #include "WM_types.h"
83 #include "UI_resources.h"
84
85
86 #include "transform.h"
87
88 static void drawObjectConstraint(TransInfo *t);
89
90 /* ************************** CONSTRAINTS ************************* */
91 void constraintAutoValues(TransInfo *t, float vec[3])
92 {
93         int mode = t->con.mode;
94         if (mode & CON_APPLY)
95         {
96                 float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
97
98                 if ((mode & CON_AXIS0) == 0)
99                 {
100                         vec[0] = nval;
101                 }
102                 if ((mode & CON_AXIS1) == 0)
103                 {
104                         vec[1] = nval;
105                 }
106                 if ((mode & CON_AXIS2) == 0)
107                 {
108                         vec[2] = nval;
109                 }
110         }
111 }
112
113 void constraintNumInput(TransInfo *t, float vec[3])
114 {
115         int mode = t->con.mode;
116         if (mode & CON_APPLY) {
117                 float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
118
119                 if (getConstraintSpaceDimension(t) == 2) {
120                         int axis = mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
121                         if (axis == (CON_AXIS0|CON_AXIS1)) {
122                                 vec[0] = vec[0];
123                                 vec[1] = vec[1];
124                                 vec[2] = nval;
125                         }
126                         else if (axis == (CON_AXIS1|CON_AXIS2)) {
127                                 vec[2] = vec[1];
128                                 vec[1] = vec[0];
129                                 vec[0] = nval;
130                         }
131                         else if (axis == (CON_AXIS0|CON_AXIS2)) {
132                                 vec[0] = vec[0];
133                                 vec[2] = vec[1];
134                                 vec[1] = nval;
135                         }
136                 }
137                 else if (getConstraintSpaceDimension(t) == 1) {
138                         if (mode & CON_AXIS0) {
139                                 vec[0] = vec[0];
140                                 vec[1] = nval;
141                                 vec[2] = nval;
142                         }
143                         else if (mode & CON_AXIS1) {
144                                 vec[1] = vec[0];
145                                 vec[0] = nval;
146                                 vec[2] = nval;
147                         }
148                         else if (mode & CON_AXIS2) {
149                                 vec[2] = vec[0];
150                                 vec[0] = nval;
151                                 vec[1] = nval;
152                         }
153                 }
154         }
155 }
156
157 static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) {
158         int i = 0;
159
160         Mat3MulVecfl(t->con.imtx, vec);
161
162         snapGrid(t, vec);
163
164         if (t->num.flag & T_NULL_ONE) {
165                 if (!(t->con.mode & CON_AXIS0))
166                         vec[0] = 1.0f;
167
168                 if (!(t->con.mode & CON_AXIS1))
169                         vec[1] = 1.0f;
170
171                 if (!(t->con.mode & CON_AXIS2))
172                         vec[2] = 1.0f;
173         }
174
175         if (hasNumInput(&t->num)) {
176                 applyNumInput(&t->num, vec);
177                 constraintNumInput(t, vec);
178         }
179
180         /* autovalues is operator param, use that directly but not if snapping is forced */
181         if (t->flag & T_AUTOVALUES && (t->tsnap.status & SNAP_FORCED) == 0)
182         {
183                 VECCOPY(vec, t->auto_values);
184                 constraintAutoValues(t, vec);
185         }
186         
187         if (t->con.mode & CON_AXIS0) {
188                 pvec[i++] = vec[0];
189         }
190         if (t->con.mode & CON_AXIS1) {
191                 pvec[i++] = vec[1];
192         }
193         if (t->con.mode & CON_AXIS2) {
194                 pvec[i++] = vec[2];
195         }
196
197         Mat3MulVecfl(t->con.mtx, vec);
198 }
199
200 static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
201         float norm[3], vec[3], factor;
202         
203         if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f)
204                 return;
205         
206         /* For when view is parallel to constraint... will cause NaNs otherwise
207            So we take vertical motion in 3D space and apply it to the
208            constraint axis. Nice for camera grab + MMB */
209         if(1.0f - fabs(Inpf(axis, t->viewinv[2])) < 0.000001f) {
210                 Projf(vec, in, t->viewinv[1]);
211                 factor = Inpf(t->viewinv[1], vec) * 2.0f;
212                 /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
213                 if(factor<0.0f) factor*= -factor;
214                 else factor*= factor;
215                 
216                 VECCOPY(out, axis);
217                 Normalize(out);
218                 VecMulf(out, -factor);  /* -factor makes move down going backwards */
219         }
220         else {
221                 float cb[3], ab[3];
222                 
223                 VECCOPY(out, axis);
224                 
225                 /* Get view vector on axis to define a plane */
226                 VecAddf(vec, t->con.center, in);
227                 getViewVector(t, vec, norm);
228                 
229                 Crossf(vec, norm, axis);
230                 
231                 /* Project input vector on the plane passing on axis */
232                 Projf(vec, in, vec);
233                 VecSubf(vec, in, vec);
234                 
235                 /* intersect the two lines: axis and norm */
236                 Crossf(cb, vec, norm);
237                 Crossf(ab, axis, norm);
238                 
239                 VecMulf(out, Inpf(cb, ab) / Inpf(ab, ab));
240         }
241 }
242
243 static void planeProjection(TransInfo *t, float in[3], float out[3]) {
244         float vec[3], factor, norm[3];
245
246         VecAddf(vec, in, t->con.center);
247         getViewVector(t, vec, norm);
248
249         VecSubf(vec, out, in);
250
251         factor = Inpf(vec, norm);
252         if (fabs(factor) <= 0.001) {
253                 return; /* prevent divide by zero */
254         }
255         factor = Inpf(vec, vec) / factor;
256
257         VECCOPY(vec, norm);
258         VecMulf(vec, factor);
259
260         VecAddf(out, in, vec);
261 }
262
263 /*
264  * Generic callback for constant spacial constraints applied to linear motion
265  * 
266  * The IN vector in projected into the constrained space and then further
267  * projected along the view vector.
268  * (in perspective mode, the view vector is relative to the position on screen)
269  *
270  */
271
272 static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
273 {
274         VECCOPY(out, in);
275         if (!td && t->con.mode & CON_APPLY) {
276                 Mat3MulVecfl(t->con.pmtx, out);
277                 
278                 // With snap, a projection is alright, no need to correct for view alignment
279                 if ((t->tsnap.status & SNAP_ON) == 0) {
280                         if (getConstraintSpaceDimension(t) == 2) {
281                                 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
282                                         planeProjection(t, in, out);
283                                 }
284                         }
285                         else if (getConstraintSpaceDimension(t) == 1) {
286                                 float c[3];
287         
288                                 if (t->con.mode & CON_AXIS0) {
289                                         VECCOPY(c, t->con.mtx[0]);
290                                 }
291                                 else if (t->con.mode & CON_AXIS1) {
292                                         VECCOPY(c, t->con.mtx[1]);
293                                 }
294                                 else if (t->con.mode & CON_AXIS2) {
295                                         VECCOPY(c, t->con.mtx[2]);
296                                 }
297                                 axisProjection(t, c, in, out);
298                         }
299                 }
300                 postConstraintChecks(t, out, pvec);
301         }
302 }
303
304 /*
305  * Generic callback for object based spacial constraints applied to linear motion
306  * 
307  * At first, the following is applied to the first data in the array
308  * The IN vector in projected into the constrained space and then further
309  * projected along the view vector.
310  * (in perspective mode, the view vector is relative to the position on screen)
311  *
312  * Further down, that vector is mapped to each data's space.
313  */
314
315 static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
316 {
317         VECCOPY(out, in);
318         if (t->con.mode & CON_APPLY) {
319                 if (!td) {
320                         Mat3MulVecfl(t->con.pmtx, out);
321                         if (getConstraintSpaceDimension(t) == 2) {
322                                 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
323                                         planeProjection(t, in, out);
324                                 }
325                         }
326                         else if (getConstraintSpaceDimension(t) == 1) {
327                                 float c[3];
328
329                                 if (t->con.mode & CON_AXIS0) {
330                                         VECCOPY(c, t->con.mtx[0]);
331                                 }
332                                 else if (t->con.mode & CON_AXIS1) {
333                                         VECCOPY(c, t->con.mtx[1]);
334                                 }
335                                 else if (t->con.mode & CON_AXIS2) {
336                                         VECCOPY(c, t->con.mtx[2]);
337                                 }
338                                 axisProjection(t, c, in, out);
339                         }
340                         postConstraintChecks(t, out, pvec);
341                         VECCOPY(out, pvec);
342                 }
343                 else {
344                         int i=0;
345
346                         out[0] = out[1] = out[2] = 0.0f;
347                         if (t->con.mode & CON_AXIS0) {
348                                 out[0] = in[i++];
349                         }
350                         if (t->con.mode & CON_AXIS1) {
351                                 out[1] = in[i++];
352                         }
353                         if (t->con.mode & CON_AXIS2) {
354                                 out[2] = in[i++];
355                         }
356                         Mat3MulVecfl(td->axismtx, out);
357                 }
358         }
359 }
360
361 /*
362  * Generic callback for constant spacial constraints applied to resize motion
363  * 
364  *
365  */
366
367 static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
368 {
369         if (!td && t->con.mode & CON_APPLY) {
370                 float tmat[3][3];
371
372                 if (!(t->con.mode & CON_AXIS0)) {
373                         smat[0][0] = 1.0f;
374                 }
375                 if (!(t->con.mode & CON_AXIS1)) {
376                         smat[1][1] = 1.0f;
377                 }
378                 if (!(t->con.mode & CON_AXIS2)) {
379                         smat[2][2] = 1.0f;
380                 }
381
382                 Mat3MulMat3(tmat, smat, t->con.imtx);
383                 Mat3MulMat3(smat, t->con.mtx, tmat);
384         }
385 }
386
387 /*
388  * Callback for object based spacial constraints applied to resize motion
389  * 
390  *
391  */
392
393 static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
394 {
395         if (td && t->con.mode & CON_APPLY) {
396                 float tmat[3][3];
397                 float imat[3][3];
398
399                 Mat3Inv(imat, td->axismtx);
400
401                 if (!(t->con.mode & CON_AXIS0)) {
402                         smat[0][0] = 1.0f;
403                 }
404                 if (!(t->con.mode & CON_AXIS1)) {
405                         smat[1][1] = 1.0f;
406                 }
407                 if (!(t->con.mode & CON_AXIS2)) {
408                         smat[2][2] = 1.0f;
409                 }
410
411                 Mat3MulMat3(tmat, smat, imat);
412                 Mat3MulMat3(smat, td->axismtx, tmat);
413         }
414 }
415
416 /*
417  * Generic callback for constant spacial constraints applied to rotations
418  * 
419  * The rotation axis is copied into VEC.
420  *
421  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
422  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
423  *
424  * The following only applies when CON_NOFLIP is not set.
425  * The vector is then modified to always point away from the screen (in global space)
426  * This insures that the rotation is always logically following the mouse.
427  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
428  */
429
430 static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
431 {
432         if (!td && t->con.mode & CON_APPLY) {
433                 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
434
435                 switch(mode) {
436                 case CON_AXIS0:
437                 case (CON_AXIS1|CON_AXIS2):
438                         VECCOPY(vec, t->con.mtx[0]);
439                         break;
440                 case CON_AXIS1:
441                 case (CON_AXIS0|CON_AXIS2):
442                         VECCOPY(vec, t->con.mtx[1]);
443                         break;
444                 case CON_AXIS2:
445                 case (CON_AXIS0|CON_AXIS1):
446                         VECCOPY(vec, t->con.mtx[2]);
447                         break;
448                 }
449                 /* don't flip axis if asked to or if num input */
450                 if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
451                         if (Inpf(vec, t->viewinv[2]) > 0.0f) {
452                                 *angle = -(*angle);
453                         }
454                 }
455         }
456 }
457
458 /*
459  * Callback for object based spacial constraints applied to rotations
460  * 
461  * The rotation axis is copied into VEC.
462  *
463  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
464  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
465  *
466  * The following only applies when CON_NOFLIP is not set.
467  * The vector is then modified to always point away from the screen (in global space)
468  * This insures that the rotation is always logically following the mouse.
469  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
470  */
471
472 static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
473 {
474         if (t->con.mode & CON_APPLY) {
475                 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
476                 
477                 /* on setup call, use first object */
478                 if (td == NULL) {
479                         td= t->data;
480                 }
481
482                 switch(mode) {
483                 case CON_AXIS0:
484                 case (CON_AXIS1|CON_AXIS2):
485                         VECCOPY(vec, td->axismtx[0]);
486                         break;
487                 case CON_AXIS1:
488                 case (CON_AXIS0|CON_AXIS2):
489                         VECCOPY(vec, td->axismtx[1]);
490                         break;
491                 case CON_AXIS2:
492                 case (CON_AXIS0|CON_AXIS1):
493                         VECCOPY(vec, td->axismtx[2]);
494                         break;
495                 }
496                 if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
497                         if (Inpf(vec, t->viewinv[2]) > 0.0f) {
498                                 *angle = -(*angle);
499                         }
500                 }
501         }
502 }
503
504 /*--------------------- INTERNAL SETUP CALLS ------------------*/
505
506 void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) {
507         strncpy(t->con.text + 1, text, 48);
508         Mat3CpyMat3(t->con.mtx, space);
509         t->con.mode = mode;
510         getConstraintMatrix(t);
511
512         startConstraint(t);
513
514         t->con.drawExtra = NULL;
515         t->con.applyVec = applyAxisConstraintVec;
516         t->con.applySize = applyAxisConstraintSize;
517         t->con.applyRot = applyAxisConstraintRot;
518         t->redraw = 1;
519 }
520
521 void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
522         if (t->flag & T_EDIT) {
523                 float obmat[3][3];
524                 Mat3CpyMat4(obmat, t->scene->obedit->obmat);
525                 setConstraint(t, obmat, mode, text);
526         }
527         else {
528                 if (t->total == 1) {
529                         setConstraint(t, t->data->axismtx, mode, text);
530                 }
531                 else {
532                         strncpy(t->con.text + 1, text, 48);
533                         Mat3CpyMat3(t->con.mtx, t->data->axismtx);
534                         t->con.mode = mode;
535                         getConstraintMatrix(t);
536
537                         startConstraint(t);
538
539                         t->con.drawExtra = drawObjectConstraint;
540                         t->con.applyVec = applyObjectConstraintVec;
541                         t->con.applySize = applyObjectConstraintSize;
542                         t->con.applyRot = applyObjectConstraintRot;
543                         t->redraw = 1;
544                 }
545         }
546 }
547
548 /*
549         Set the constraint according to the user defined orientation
550
551         ftext is a format string passed to sprintf. It will add the name of
552         the orientation where %s is (logically).
553 */
554 void setUserConstraint(TransInfo *t, int mode, const char ftext[]) {
555         char text[40];
556         //short twmode= (t->spacetype==SPACE_VIEW3D)? ((View3D*)t->view)->twmode: V3D_MANIP_GLOBAL;
557
558         switch(t->current_orientation) {
559         case V3D_MANIP_GLOBAL:
560                 {
561                         float mtx[3][3];
562                         sprintf(text, ftext, "global");
563                         Mat3One(mtx);
564                         setConstraint(t, mtx, mode, text);
565                 }
566                 break;
567         case V3D_MANIP_LOCAL:
568                 sprintf(text, ftext, "local");
569                 setLocalConstraint(t, mode, text);
570                 break;
571         case V3D_MANIP_NORMAL:
572                 sprintf(text, ftext, "normal");
573                 setConstraint(t, t->spacemtx, mode, text);
574                 break;
575         case V3D_MANIP_VIEW:
576                 sprintf(text, ftext, "view");
577                 setConstraint(t, t->spacemtx, mode, text);
578                 break;
579         default: /* V3D_MANIP_CUSTOM */
580                 sprintf(text, ftext, t->spacename);
581                 setConstraint(t, t->spacemtx, mode, text);
582                 break;
583         }
584
585         t->con.mode |= CON_USER;
586 }
587
588 /*--------------------- EXTERNAL SETUP CALLS ------------------*/
589
590 void BIF_setLocalLockConstraint(char axis, char *text) {
591         TransInfo *t = BIF_GetTransInfo();
592
593         if (t->total == 0) {
594                 return;
595         }
596         
597         switch (axis) {
598         case 'x':
599                 setLocalConstraint(t, (CON_AXIS1|CON_AXIS2), text);
600                 break;
601         case 'y':
602                 setLocalConstraint(t, (CON_AXIS0|CON_AXIS2), text);
603                 break;
604         case 'z':
605                 setLocalConstraint(t, (CON_AXIS0|CON_AXIS1), text);
606                 break;
607         }
608 }
609
610 void BIF_setLocalAxisConstraint(char axis, char *text) {
611         TransInfo *t = BIF_GetTransInfo();
612
613         if (t->total == 0) {
614                 return;
615         }
616         
617         switch (axis) {
618         case 'X':
619                 setLocalConstraint(t, CON_AXIS0, text);
620                 break;
621         case 'Y':
622                 setLocalConstraint(t, CON_AXIS1, text);
623                 break;
624         case 'Z':
625                 setLocalConstraint(t, CON_AXIS2, text);
626                 break;
627         }
628 }
629
630 /* text is optional, for header print */
631 void BIF_setSingleAxisConstraint(float vec[3], char *text) {
632         TransInfo *t = BIF_GetTransInfo();
633         float space[3][3], v[3];
634         
635         if (t->total == 0) {
636                 return;
637         }
638         
639         VECCOPY(space[0], vec);
640
641         v[0] = vec[2];
642         v[1] = vec[0];
643         v[2] = vec[1];
644
645         Crossf(space[1], vec, v);
646         Crossf(space[2], vec, space[1]);
647         Mat3Ortho(space);
648
649         Mat3CpyMat3(t->con.mtx, space);
650         t->con.mode = CON_AXIS0;
651         
652         getConstraintMatrix(t);
653
654         startConstraint(t);
655         
656         /* start copying with an offset of 1, to reserve a spot for the SPACE char */
657         if(text)
658         {
659                 strncpy(t->con.text+1, text, 48);       /* 50 in struct */
660         }
661         else
662         {
663                 t->con.text[1] = '\0'; /* No text */
664         }
665         
666         t->con.drawExtra = NULL;
667         t->con.applyVec = applyAxisConstraintVec;
668         t->con.applySize = applyAxisConstraintSize;
669         t->con.applyRot = applyAxisConstraintRot;
670         t->redraw = 1;
671 }
672
673 void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text) {
674         TransInfo *t = BIF_GetTransInfo();
675         float space[3][3];
676         
677         if (t->total == 0) {
678                 return;
679         }
680
681         VECCOPY(space[0], vec1);
682         VECCOPY(space[1], vec2);
683         Crossf(space[2], space[0], space[1]);
684         Mat3Ortho(space);
685         
686         Mat3CpyMat3(t->con.mtx, space);
687         t->con.mode = CON_AXIS0|CON_AXIS1;
688
689         getConstraintMatrix(t);
690
691         startConstraint(t);
692         
693         /* start copying with an offset of 1, to reserve a spot for the SPACE char */
694         if(text)
695         {
696                 strncpy(t->con.text+1, text, 48);       /* 50 in struct */
697         }
698         else
699         {
700                 t->con.text[1] = '\0'; /* No text */
701         }
702
703         t->con.drawExtra = NULL;
704         t->con.applyVec = applyAxisConstraintVec;
705         t->con.applySize = applyAxisConstraintSize;
706         t->con.applyRot = applyAxisConstraintRot;
707         t->redraw = 1;
708 }
709
710 /*----------------- DRAWING CONSTRAINTS -------------------*/
711
712 void drawConstraint(const struct bContext *C, TransInfo *t)
713 {
714         TransCon *tc = &(t->con);
715
716         if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE))
717                 return;
718         if (!(tc->mode & CON_APPLY))
719                 return;
720         if (t->flag & T_USES_MANIPULATOR)
721                 return;
722         if (t->flag & T_NO_CONSTRAINT)
723                 return;
724         
725         /* nasty exception for Z constraint in camera view */
726         // TRANSFORM_FIX_ME
727 //      if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp==V3D_CAMOB) 
728 //              return;
729
730         if (tc->drawExtra) {
731                 tc->drawExtra(t);
732         }
733         else {
734                 if (tc->mode & CON_SELECT) {
735                         float vec[3];
736                         char col2[3] = {255,255,255};
737                         convertViewVec(t, vec, (short)(t->mval[0] - t->con.imval[0]), (short)(t->mval[1] - t->con.imval[1]));
738                         VecAddf(vec, vec, tc->center);
739
740                         drawLine(t, tc->center, tc->mtx[0], 'x', 0);
741                         drawLine(t, tc->center, tc->mtx[1], 'y', 0);
742                         drawLine(t, tc->center, tc->mtx[2], 'z', 0);
743
744                         glColor3ubv((GLubyte *)col2);
745                         
746                         glDisable(GL_DEPTH_TEST);
747                         setlinestyle(1);
748                         glBegin(GL_LINE_STRIP); 
749                                 glVertex3fv(tc->center); 
750                                 glVertex3fv(vec); 
751                         glEnd();
752                         setlinestyle(0);
753                         // TRANSFORM_FIX_ME
754                         //if(G.vd->zbuf)
755                                 glEnable(GL_DEPTH_TEST);        
756                 }
757
758                 if (tc->mode & CON_AXIS0) {
759                         drawLine(t, tc->center, tc->mtx[0], 'x', DRAWLIGHT);
760                 }
761                 if (tc->mode & CON_AXIS1) {
762                         drawLine(t, tc->center, tc->mtx[1], 'y', DRAWLIGHT);
763                 }
764                 if (tc->mode & CON_AXIS2) {
765                         drawLine(t, tc->center, tc->mtx[2], 'z', DRAWLIGHT);
766                 }
767         }
768 }
769
770 /* called from drawview.c, as an extra per-window draw option */
771 void drawPropCircle(const struct bContext *C, TransInfo *t)
772 {
773         if (t->flag & T_PROP_EDIT) {
774                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
775                 float tmat[4][4], imat[4][4];
776
777                 UI_ThemeColor(TH_GRID);
778                 
779                 if(t->spacetype == SPACE_VIEW3D && rv3d != NULL)
780                 {
781                         Mat4CpyMat4(tmat, rv3d->viewmat);
782                         Mat4Invert(imat, tmat);
783                 }
784                 else
785                 {
786                         Mat4One(tmat);
787                         Mat4One(imat);
788                 }
789
790                 glPushMatrix();
791
792                 if((t->spacetype == SPACE_VIEW3D) && t->obedit)
793                 {
794                         glMultMatrixf(t->obedit->obmat); /* because t->center is in local space */
795                 }
796                 else if(t->spacetype == SPACE_IMAGE)
797                 {
798                         float aspx, aspy;
799
800                         ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
801                         glScalef(1.0f/aspx, 1.0f/aspy, 1.0);
802                 }
803
804                 set_inverted_drawing(1);
805                 drawcircball(GL_LINE_LOOP, t->center, t->prop_size, imat);
806                 set_inverted_drawing(0);
807                 
808                 glPopMatrix();
809         }
810 }
811
812 void BIF_getPropCenter(float *center)
813 {
814         TransInfo *t = BIF_GetTransInfo();
815
816         if (t && t->flag & T_PROP_EDIT) {
817                 VECCOPY(center, t->center);
818         }
819         else
820                 center[0] = center[1] = center[2] = 0.0f;
821 }
822
823 static void drawObjectConstraint(TransInfo *t) {
824         int i;
825         TransData * td = t->data;
826
827         /* Draw the first one lighter because that's the one who controls the others.
828            Meaning the transformation is projected on that one and just copied on the others
829            constraint space.
830            In a nutshell, the object with light axis is controlled by the user and the others follow.
831            Without drawing the first light, users have little clue what they are doing.
832          */
833         if (t->con.mode & CON_AXIS0) {
834                 drawLine(t, td->ob->obmat[3], td->axismtx[0], 'x', DRAWLIGHT);
835         }
836         if (t->con.mode & CON_AXIS1) {
837                 drawLine(t, td->ob->obmat[3], td->axismtx[1], 'y', DRAWLIGHT);
838         }
839         if (t->con.mode & CON_AXIS2) {
840                 drawLine(t, td->ob->obmat[3], td->axismtx[2], 'z', DRAWLIGHT);
841         }
842         
843         td++;
844
845         for(i=1;i<t->total;i++,td++) {
846                 if (t->con.mode & CON_AXIS0) {
847                         drawLine(t, td->ob->obmat[3], td->axismtx[0], 'x', 0);
848                 }
849                 if (t->con.mode & CON_AXIS1) {
850                         drawLine(t, td->ob->obmat[3], td->axismtx[1], 'y', 0);
851                 }
852                 if (t->con.mode & CON_AXIS2) {
853                         drawLine(t, td->ob->obmat[3], td->axismtx[2], 'z', 0);
854                 }
855         }
856 }
857
858 /*--------------------- START / STOP CONSTRAINTS ---------------------- */
859
860 void startConstraint(TransInfo *t) {
861         t->con.mode |= CON_APPLY;
862         *t->con.text = ' ';
863         t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
864 }
865
866 void stopConstraint(TransInfo *t) {
867         t->con.mode &= ~(CON_APPLY|CON_SELECT);
868         *t->con.text = '\0';
869         t->num.idx_max = t->idx_max;
870 }
871
872 void getConstraintMatrix(TransInfo *t)
873 {
874         float mat[3][3];
875         Mat3Inv(t->con.imtx, t->con.mtx);
876         Mat3One(t->con.pmtx);
877
878         if (!(t->con.mode & CON_AXIS0)) {
879                 t->con.pmtx[0][0]               =
880                         t->con.pmtx[0][1]       =
881                         t->con.pmtx[0][2]       = 0.0f;
882         }
883
884         if (!(t->con.mode & CON_AXIS1)) {
885                 t->con.pmtx[1][0]               =
886                         t->con.pmtx[1][1]       =
887                         t->con.pmtx[1][2]       = 0.0f;
888         }
889
890         if (!(t->con.mode & CON_AXIS2)) {
891                 t->con.pmtx[2][0]               =
892                         t->con.pmtx[2][1]       =
893                         t->con.pmtx[2][2]       = 0.0f;
894         }
895
896         Mat3MulMat3(mat, t->con.pmtx, t->con.imtx);
897         Mat3MulMat3(t->con.pmtx, t->con.mtx, mat);
898 }
899
900 /*------------------------- MMB Select -------------------------------*/
901
902 void initSelectConstraint(TransInfo *t, float mtx[3][3])
903 {
904         Mat3CpyMat3(t->con.mtx, mtx);
905         t->con.mode |= CON_APPLY;
906         t->con.mode |= CON_SELECT;
907
908         setNearestAxis(t);
909         t->con.drawExtra = NULL;
910         t->con.applyVec = applyAxisConstraintVec;
911         t->con.applySize = applyAxisConstraintSize;
912         t->con.applyRot = applyAxisConstraintRot;
913 }
914
915 void selectConstraint(TransInfo *t) {
916         if (t->con.mode & CON_SELECT) {
917                 setNearestAxis(t);
918                 startConstraint(t);
919         }
920 }
921
922 void postSelectConstraint(TransInfo *t)
923 {
924         if (!(t->con.mode & CON_SELECT))
925                 return;
926
927         t->con.mode &= ~CON_AXIS0;
928         t->con.mode &= ~CON_AXIS1;
929         t->con.mode &= ~CON_AXIS2;
930         t->con.mode &= ~CON_SELECT;
931
932         setNearestAxis(t);
933
934         startConstraint(t);
935         t->redraw = 1;
936 }
937
938 static void setNearestAxis2d(TransInfo *t)
939 {
940         /* no correction needed... just use whichever one is lower */
941         if ( abs(t->mval[0]-t->con.imval[0]) < abs(t->mval[1]-t->con.imval[1]) ) {
942                 t->con.mode |= CON_AXIS1;
943                 sprintf(t->con.text, " along Y axis");
944         }
945         else {
946                 t->con.mode |= CON_AXIS0;
947                 sprintf(t->con.text, " along X axis");
948         }
949 }
950
951 static void setNearestAxis3d(TransInfo *t)
952 {
953         float zfac;
954         float mvec[3], axis[3], proj[3];
955         float len[3];
956         int i, icoord[2];
957         
958         /* calculate mouse movement */
959         mvec[0] = (float)(t->mval[0] - t->con.imval[0]);
960         mvec[1] = (float)(t->mval[1] - t->con.imval[1]);
961         mvec[2] = 0.0f;
962         
963         /* we need to correct axis length for the current zoomlevel of view,
964            this to prevent projected values to be clipped behind the camera
965            and to overflow the short integers.
966            The formula used is a bit stupid, just a simplification of the substraction
967            of two 2D points 30 pixels apart (that's the last factor in the formula) after
968            projecting them with window_to_3d_delta and then get the length of that vector.
969         */
970         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];
971         zfac = VecLength(t->persinv[0]) * 2.0f/t->ar->winx * zfac * 30.0f;
972
973         for (i = 0; i<3; i++) {
974                 VECCOPY(axis, t->con.mtx[i]);
975                 
976                 VecMulf(axis, zfac);
977                 /* now we can project to get window coordinate */
978                 VecAddf(axis, axis, t->con.center);
979                 projectIntView(t, axis, icoord);
980                 
981                 axis[0] = (float)(icoord[0] - t->center2d[0]);
982                 axis[1] = (float)(icoord[1] - t->center2d[1]);
983                 axis[2] = 0.0f;
984
985                 if (Normalize(axis) != 0.0f) {
986                         Projf(proj, mvec, axis);
987                         VecSubf(axis, mvec, proj);
988                         len[i] = Normalize(axis);
989                 }
990                 else {
991                         len[i] = 10000000000.0f;
992                 }
993         }
994
995         if (len[0] <= len[1] && len[0] <= len[2]) {
996                 if (t->modifiers & MOD_CONSTRAINT_PLANE) {
997                         t->con.mode |= (CON_AXIS1|CON_AXIS2);
998                         sprintf(t->con.text, " locking %s X axis", t->spacename);
999                 }
1000                 else {
1001                         t->con.mode |= CON_AXIS0;
1002                         sprintf(t->con.text, " along %s X axis", t->spacename);
1003                 }
1004         }
1005         else if (len[1] <= len[0] && len[1] <= len[2]) {
1006                 if (t->modifiers & MOD_CONSTRAINT_PLANE) {
1007                         t->con.mode |= (CON_AXIS0|CON_AXIS2);
1008                         sprintf(t->con.text, " locking %s Y axis", t->spacename);
1009                 }
1010                 else {
1011                         t->con.mode |= CON_AXIS1;
1012                         sprintf(t->con.text, " along %s Y axis", t->spacename);
1013                 }
1014         }
1015         else if (len[2] <= len[1] && len[2] <= len[0]) {
1016                 if (t->modifiers & MOD_CONSTRAINT_PLANE) {
1017                         t->con.mode |= (CON_AXIS0|CON_AXIS1);
1018                         sprintf(t->con.text, " locking %s Z axis", t->spacename);
1019                 }
1020                 else {
1021                         t->con.mode |= CON_AXIS2;
1022                         sprintf(t->con.text, " along %s Z axis", t->spacename);
1023                 }
1024         }
1025 }
1026
1027 void setNearestAxis(TransInfo *t)
1028 {
1029         /* clear any prior constraint flags */
1030         t->con.mode &= ~CON_AXIS0;
1031         t->con.mode &= ~CON_AXIS1;
1032         t->con.mode &= ~CON_AXIS2;
1033
1034         /* constraint setting - depends on spacetype */
1035         if (t->spacetype == SPACE_VIEW3D) {
1036                 /* 3d-view */
1037                 setNearestAxis3d(t);    
1038         }
1039         else {
1040                 /* assume that this means a 2D-Editor */
1041                 setNearestAxis2d(t);
1042         }
1043         
1044         getConstraintMatrix(t);
1045 }
1046
1047 /*-------------- HELPER FUNCTIONS ----------------*/
1048
1049 char constraintModeToChar(TransInfo *t) {
1050         if ((t->con.mode & CON_APPLY)==0) {
1051                 return '\0';
1052         }
1053         switch (t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2)) {
1054         case (CON_AXIS0):
1055         case (CON_AXIS1|CON_AXIS2):
1056                 return 'X';
1057         case (CON_AXIS1):
1058         case (CON_AXIS0|CON_AXIS2):
1059                 return 'Y';
1060         case (CON_AXIS2):
1061         case (CON_AXIS0|CON_AXIS1):
1062                 return 'Z';
1063         default:
1064                 return '\0';
1065         }
1066 }
1067
1068
1069 int isLockConstraint(TransInfo *t) {
1070         int mode = t->con.mode;
1071
1072         if ( (mode & (CON_AXIS0|CON_AXIS1)) == (CON_AXIS0|CON_AXIS1))
1073                 return 1;
1074
1075         if ( (mode & (CON_AXIS1|CON_AXIS2)) == (CON_AXIS1|CON_AXIS2))
1076                 return 1;
1077
1078         if ( (mode & (CON_AXIS0|CON_AXIS2)) == (CON_AXIS0|CON_AXIS2))
1079                 return 1;
1080
1081         return 0;
1082 }
1083
1084 /*
1085  * Returns the dimension of the constraint space.
1086  * 
1087  * For that reason, the flags always needs to be set to properly evaluate here,
1088  * even if they aren't actually used in the callback function. (Which could happen
1089  * for weird constraints not yet designed. Along a path for example.)
1090  */
1091
1092 int getConstraintSpaceDimension(TransInfo *t)
1093 {
1094         int n = 0;
1095
1096         if (t->con.mode & CON_AXIS0)
1097                 n++;
1098
1099         if (t->con.mode & CON_AXIS1)
1100                 n++;
1101
1102         if (t->con.mode & CON_AXIS2)
1103                 n++;
1104
1105         return n;
1106 /*
1107   Someone willing to do it criptically could do the following instead:
1108
1109   return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
1110         
1111   Based on the assumptions that the axis flags are one after the other and start at 1
1112 */
1113 }